| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 // Check that the object is a JS array. | 182 // Check that the object is a JS array. |
| 183 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE); | 183 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE); |
| 184 __ b(ne, miss_label); | 184 __ b(ne, miss_label); |
| 185 | 185 |
| 186 // Load length directly from the JS array. | 186 // Load length directly from the JS array. |
| 187 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); | 187 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
| 188 __ Ret(); | 188 __ Ret(); |
| 189 } | 189 } |
| 190 | 190 |
| 191 | 191 |
| 192 // Generate code to check if an object is a string. If the object is | 192 // Generate code to check if an object is a string. If the object is a |
| 193 // a string, the map's instance type is left in the scratch1 register. | 193 // heap object, its map's instance type is left in the scratch1 register. |
| 194 // If this is not needed, scratch1 and scratch2 may be the same register. |
| 194 static void GenerateStringCheck(MacroAssembler* masm, | 195 static void GenerateStringCheck(MacroAssembler* masm, |
| 195 Register receiver, | 196 Register receiver, |
| 196 Register scratch1, | 197 Register scratch1, |
| 197 Register scratch2, | 198 Register scratch2, |
| 198 Label* smi, | 199 Label* smi, |
| 199 Label* non_string_object) { | 200 Label* non_string_object) { |
| 200 // Check that the receiver isn't a smi. | 201 // Check that the receiver isn't a smi. |
| 201 __ tst(receiver, Operand(kSmiTagMask)); | 202 __ tst(receiver, Operand(kSmiTagMask)); |
| 202 __ b(eq, smi); | 203 __ b(eq, smi); |
| 203 | 204 |
| 204 // Check that the object is a string. | 205 // Check that the object is a string. |
| 205 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset)); | 206 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| 206 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); | 207 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); |
| 207 __ and_(scratch2, scratch1, Operand(kIsNotStringMask)); | 208 __ and_(scratch2, scratch1, Operand(kIsNotStringMask)); |
| 208 // The cast is to resolve the overload for the argument of 0x0. | 209 // The cast is to resolve the overload for the argument of 0x0. |
| 209 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag))); | 210 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag))); |
| 210 __ b(ne, non_string_object); | 211 __ b(ne, non_string_object); |
| 211 } | 212 } |
| 212 | 213 |
| 213 | 214 |
| 214 // Generate code to load the length from a string object and return the length. | 215 // Generate code to load the length from a string object and return the length. |
| 215 // If the receiver object is not a string or a wrapped string object the | 216 // If the receiver object is not a string or a wrapped string object the |
| 216 // execution continues at the miss label. The register containing the | 217 // execution continues at the miss label. The register containing the |
| 217 // receiver is potentially clobbered. | 218 // receiver is potentially clobbered. |
| 218 void StubCompiler::GenerateLoadStringLength2(MacroAssembler* masm, | 219 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, |
| 219 Register receiver, | 220 Register receiver, |
| 220 Register scratch1, | 221 Register scratch1, |
| 221 Register scratch2, | 222 Register scratch2, |
| 222 Label* miss) { | 223 Label* miss) { |
| 223 Label check_string, check_wrapper; | 224 Label check_wrapper; |
| 224 | 225 |
| 225 __ bind(&check_string); | |
| 226 // Check if the object is a string leaving the instance type in the | 226 // Check if the object is a string leaving the instance type in the |
| 227 // scratch1 register. | 227 // scratch1 register. |
| 228 GenerateStringCheck(masm, receiver, scratch1, scratch2, | 228 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, &check_wrapper); |
| 229 miss, &check_wrapper); | |
| 230 | 229 |
| 231 // Load length directly from the string. | 230 // Load length directly from the string. |
| 232 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset)); | 231 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset)); |
| 233 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); | 232 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
| 234 __ Ret(); | 233 __ Ret(); |
| 235 | 234 |
| 236 // Check if the object is a JSValue wrapper. | 235 // Check if the object is a JSValue wrapper. |
| 237 __ bind(&check_wrapper); | 236 __ bind(&check_wrapper); |
| 238 __ cmp(scratch1, Operand(JS_VALUE_TYPE)); | 237 __ cmp(scratch1, Operand(JS_VALUE_TYPE)); |
| 239 __ b(ne, miss); | 238 __ b(ne, miss); |
| 240 | 239 |
| 241 // Unwrap the value in place and check if the wrapped value is a string. | 240 // Unwrap the value and check if the wrapped value is a string. |
| 242 __ ldr(receiver, FieldMemOperand(receiver, JSValue::kValueOffset)); | 241 __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset)); |
| 243 __ b(&check_string); | 242 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss); |
| 243 __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset)); |
| 244 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
| 245 __ Ret(); |
| 244 } | 246 } |
| 245 | 247 |
| 246 | 248 |
| 247 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, | 249 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, |
| 248 Register receiver, | 250 Register receiver, |
| 249 Register scratch1, | 251 Register scratch1, |
| 250 Register scratch2, | 252 Register scratch2, |
| 251 Label* miss_label) { | 253 Label* miss_label) { |
| 252 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); | 254 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); |
| 253 __ mov(r0, scratch1); | 255 __ mov(r0, scratch1); |
| 254 __ Ret(); | 256 __ Ret(); |
| 255 } | 257 } |
| 256 | 258 |
| 257 | 259 |
| 258 // Generate StoreField code, value is passed in r0 register. | 260 // Generate StoreField code, value is passed in r0 register. |
| 259 // After executing generated code, the receiver_reg and name_reg | 261 // When leaving generated code after success, the receiver_reg and name_reg |
| 260 // may be clobbered. | 262 // may be clobbered. Upon branch to miss_label, the receiver and name |
| 263 // registers have their original values. |
| 261 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | 264 void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
| 262 Builtins::Name storage_extend, | |
| 263 JSObject* object, | 265 JSObject* object, |
| 264 int index, | 266 int index, |
| 265 Map* transition, | 267 Map* transition, |
| 266 Register receiver_reg, | 268 Register receiver_reg, |
| 267 Register name_reg, | 269 Register name_reg, |
| 268 Register scratch, | 270 Register scratch, |
| 269 Label* miss_label) { | 271 Label* miss_label) { |
| 270 // r0 : value | 272 // r0 : value |
| 271 Label exit; | 273 Label exit; |
| 272 | 274 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 285 } | 287 } |
| 286 | 288 |
| 287 // Stub never generated for non-global objects that require access | 289 // Stub never generated for non-global objects that require access |
| 288 // checks. | 290 // checks. |
| 289 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 291 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
| 290 | 292 |
| 291 // Perform map transition for the receiver if necessary. | 293 // Perform map transition for the receiver if necessary. |
| 292 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) { | 294 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) { |
| 293 // The properties must be extended before we can store the value. | 295 // The properties must be extended before we can store the value. |
| 294 // We jump to a runtime call that extends the properties array. | 296 // We jump to a runtime call that extends the properties array. |
| 297 __ push(receiver_reg); |
| 295 __ mov(r2, Operand(Handle<Map>(transition))); | 298 __ mov(r2, Operand(Handle<Map>(transition))); |
| 296 // Please note, if we implement keyed store for arm we need | 299 __ stm(db_w, sp, r2.bit() | r0.bit()); |
| 297 // to call the Builtins::KeyedStoreIC_ExtendStorage. | 300 __ TailCallRuntime( |
| 298 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage)); | 301 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)), |
| 299 __ Jump(ic, RelocInfo::CODE_TARGET); | 302 3, 1); |
| 300 return; | 303 return; |
| 301 } | 304 } |
| 302 | 305 |
| 303 if (transition != NULL) { | 306 if (transition != NULL) { |
| 304 // Update the map of the object; no write barrier updating is | 307 // Update the map of the object; no write barrier updating is |
| 305 // needed because the map is never in new space. | 308 // needed because the map is never in new space. |
| 306 __ mov(ip, Operand(Handle<Map>(transition))); | 309 __ mov(ip, Operand(Handle<Map>(transition))); |
| 307 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); | 310 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); |
| 308 } | 311 } |
| 309 | 312 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 Object* object, | 369 Object* object, |
| 367 const ParameterCount& arguments, | 370 const ParameterCount& arguments, |
| 368 Label* miss) { | 371 Label* miss) { |
| 369 // ----------- S t a t e ------------- | 372 // ----------- S t a t e ------------- |
| 370 // -- r0: receiver | 373 // -- r0: receiver |
| 371 // -- r1: function to call | 374 // -- r1: function to call |
| 372 // ----------------------------------- | 375 // ----------------------------------- |
| 373 | 376 |
| 374 // Check that the function really is a function. | 377 // Check that the function really is a function. |
| 375 __ BranchOnSmi(r1, miss); | 378 __ BranchOnSmi(r1, miss); |
| 376 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); | 379 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE); |
| 377 __ b(ne, miss); | 380 __ b(ne, miss); |
| 378 | 381 |
| 379 // Patch the receiver on the stack with the global proxy if | 382 // Patch the receiver on the stack with the global proxy if |
| 380 // necessary. | 383 // necessary. |
| 381 if (object->IsGlobalObject()) { | 384 if (object->IsGlobalObject()) { |
| 382 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset)); | 385 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset)); |
| 383 __ str(r3, MemOperand(sp, arguments.immediate() * kPointerSize)); | 386 __ str(r3, MemOperand(sp, arguments.immediate() * kPointerSize)); |
| 384 } | 387 } |
| 385 | 388 |
| 386 // Invoke the function. | 389 // Invoke the function. |
| 387 __ InvokeFunction(r1, arguments, JUMP_FUNCTION); | 390 __ InvokeFunction(r1, arguments, JUMP_FUNCTION); |
| 388 } | 391 } |
| 389 | 392 |
| 390 | 393 |
| 391 static void GenerateCallConstFunction(MacroAssembler* masm, | |
| 392 JSFunction* function, | |
| 393 const ParameterCount& arguments) { | |
| 394 ASSERT(function->is_compiled()); | |
| 395 | |
| 396 // Get the function and setup the context. | |
| 397 __ mov(r1, Operand(Handle<JSFunction>(function))); | |
| 398 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); | |
| 399 | |
| 400 // Jump to the cached code (tail call). | |
| 401 Handle<Code> code(function->code()); | |
| 402 ParameterCount expected(function->shared()->formal_parameter_count()); | |
| 403 __ InvokeCode(code, expected, arguments, | |
| 404 RelocInfo::CODE_TARGET, JUMP_FUNCTION); | |
| 405 } | |
| 406 | |
| 407 | |
| 408 template <class Compiler> | |
| 409 static void CompileLoadInterceptor(Compiler* compiler, | |
| 410 StubCompiler* stub_compiler, | |
| 411 MacroAssembler* masm, | |
| 412 JSObject* object, | |
| 413 JSObject* holder, | |
| 414 String* name, | |
| 415 LookupResult* lookup, | |
| 416 Register receiver, | |
| 417 Register scratch1, | |
| 418 Register scratch2, | |
| 419 Label* miss) { | |
| 420 ASSERT(holder->HasNamedInterceptor()); | |
| 421 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | |
| 422 | |
| 423 // Check that the receiver isn't a smi. | |
| 424 __ BranchOnSmi(receiver, miss); | |
| 425 | |
| 426 // Check that the maps haven't changed. | |
| 427 Register reg = | |
| 428 stub_compiler->CheckPrototypes(object, receiver, holder, | |
| 429 scratch1, scratch2, name, miss); | |
| 430 | |
| 431 if (lookup->IsValid() && lookup->IsCacheable()) { | |
| 432 compiler->CompileCacheable(masm, | |
| 433 stub_compiler, | |
| 434 receiver, | |
| 435 reg, | |
| 436 scratch1, | |
| 437 scratch2, | |
| 438 holder, | |
| 439 lookup, | |
| 440 name, | |
| 441 miss); | |
| 442 } else { | |
| 443 compiler->CompileRegular(masm, | |
| 444 receiver, | |
| 445 reg, | |
| 446 scratch2, | |
| 447 holder, | |
| 448 miss); | |
| 449 } | |
| 450 } | |
| 451 | |
| 452 | |
| 453 static void PushInterceptorArguments(MacroAssembler* masm, | 394 static void PushInterceptorArguments(MacroAssembler* masm, |
| 454 Register receiver, | 395 Register receiver, |
| 455 Register holder, | 396 Register holder, |
| 456 Register name, | 397 Register name, |
| 457 JSObject* holder_obj) { | 398 JSObject* holder_obj) { |
| 458 __ push(receiver); | 399 __ push(receiver); |
| 459 __ push(holder); | 400 __ push(holder); |
| 460 __ push(name); | 401 __ push(name); |
| 461 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor(); | 402 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor(); |
| 462 ASSERT(!Heap::InNewSpace(interceptor)); | 403 ASSERT(!Heap::InNewSpace(interceptor)); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 493 void CompileCacheable(MacroAssembler* masm, | 434 void CompileCacheable(MacroAssembler* masm, |
| 494 StubCompiler* stub_compiler, | 435 StubCompiler* stub_compiler, |
| 495 Register receiver, | 436 Register receiver, |
| 496 Register holder, | 437 Register holder, |
| 497 Register scratch1, | 438 Register scratch1, |
| 498 Register scratch2, | 439 Register scratch2, |
| 499 JSObject* holder_obj, | 440 JSObject* holder_obj, |
| 500 LookupResult* lookup, | 441 LookupResult* lookup, |
| 501 String* name, | 442 String* name, |
| 502 Label* miss_label) { | 443 Label* miss_label) { |
| 503 AccessorInfo* callback = 0; | 444 AccessorInfo* callback = NULL; |
| 504 bool optimize = false; | 445 bool optimize = false; |
| 505 // So far the most popular follow ups for interceptor loads are FIELD | 446 // So far the most popular follow ups for interceptor loads are FIELD |
| 506 // and CALLBACKS, so inline only them, other cases may be added | 447 // and CALLBACKS, so inline only them, other cases may be added |
| 507 // later. | 448 // later. |
| 508 if (lookup->type() == FIELD) { | 449 if (lookup->type() == FIELD) { |
| 509 optimize = true; | 450 optimize = true; |
| 510 } else if (lookup->type() == CALLBACKS) { | 451 } else if (lookup->type() == CALLBACKS) { |
| 511 Object* callback_object = lookup->GetCallbackObject(); | 452 Object* callback_object = lookup->GetCallbackObject(); |
| 512 if (callback_object->IsAccessorInfo()) { | 453 if (callback_object->IsAccessorInfo()) { |
| 513 callback = AccessorInfo::cast(callback_object); | 454 callback = AccessorInfo::cast(callback_object); |
| 514 optimize = callback->getter() != NULL; | 455 optimize = callback->getter() != NULL; |
| 515 } | 456 } |
| 516 } | 457 } |
| 517 | 458 |
| 518 if (!optimize) { | 459 if (!optimize) { |
| 519 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); | 460 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); |
| 520 return; | 461 return; |
| 521 } | 462 } |
| 522 | 463 |
| 523 // Note: starting a frame here makes GC aware of pointers pushed below. | 464 // Note: starting a frame here makes GC aware of pointers pushed below. |
| 524 __ EnterInternalFrame(); | 465 __ EnterInternalFrame(); |
| 525 | 466 |
| 526 if (lookup->type() == CALLBACKS) { | 467 __ push(receiver); |
| 527 __ push(receiver); | |
| 528 } | |
| 529 __ push(holder); | 468 __ push(holder); |
| 530 __ push(name_); | 469 __ push(name_); |
| 531 | 470 |
| 532 CompileCallLoadPropertyWithInterceptor(masm, | 471 CompileCallLoadPropertyWithInterceptor(masm, |
| 533 receiver, | 472 receiver, |
| 534 holder, | 473 holder, |
| 535 name_, | 474 name_, |
| 536 holder_obj); | 475 holder_obj); |
| 537 | 476 |
| 538 Label interceptor_failed; | 477 Label interceptor_failed; |
| 539 // Compare with no_interceptor_result_sentinel. | 478 // Compare with no_interceptor_result_sentinel. |
| 540 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex); | 479 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex); |
| 541 __ cmp(r0, scratch1); | 480 __ cmp(r0, scratch1); |
| 542 __ b(eq, &interceptor_failed); | 481 __ b(eq, &interceptor_failed); |
| 543 __ LeaveInternalFrame(); | 482 __ LeaveInternalFrame(); |
| 544 __ Ret(); | 483 __ Ret(); |
| 545 | 484 |
| 546 __ bind(&interceptor_failed); | 485 __ bind(&interceptor_failed); |
| 547 __ pop(name_); | 486 __ pop(name_); |
| 548 __ pop(holder); | 487 __ pop(holder); |
| 549 | 488 __ pop(receiver); |
| 550 if (lookup->type() == CALLBACKS) { | |
| 551 __ pop(receiver); | |
| 552 } | |
| 553 | 489 |
| 554 __ LeaveInternalFrame(); | 490 __ LeaveInternalFrame(); |
| 555 | 491 |
| 556 if (lookup->type() == FIELD) { | 492 if (lookup->type() == FIELD) { |
| 557 holder = stub_compiler->CheckPrototypes(holder_obj, | 493 holder = stub_compiler->CheckPrototypes(holder_obj, |
| 558 holder, | 494 holder, |
| 559 lookup->holder(), | 495 lookup->holder(), |
| 560 scratch1, | 496 scratch1, |
| 561 scratch2, | 497 scratch2, |
| 562 name, | 498 name, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 614 ExternalReference ref = ExternalReference( | 550 ExternalReference ref = ExternalReference( |
| 615 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); | 551 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); |
| 616 __ TailCallRuntime(ref, 5, 1); | 552 __ TailCallRuntime(ref, 5, 1); |
| 617 } | 553 } |
| 618 | 554 |
| 619 private: | 555 private: |
| 620 Register name_; | 556 Register name_; |
| 621 }; | 557 }; |
| 622 | 558 |
| 623 | 559 |
| 624 class CallInterceptorCompiler BASE_EMBEDDED { | 560 static void CompileLoadInterceptor(LoadInterceptorCompiler* compiler, |
| 625 public: | 561 StubCompiler* stub_compiler, |
| 626 CallInterceptorCompiler(const ParameterCount& arguments, Register name) | 562 MacroAssembler* masm, |
| 627 : arguments_(arguments), argc_(arguments.immediate()), name_(name) {} | 563 JSObject* object, |
| 564 JSObject* holder, |
| 565 String* name, |
| 566 LookupResult* lookup, |
| 567 Register receiver, |
| 568 Register scratch1, |
| 569 Register scratch2, |
| 570 Label* miss) { |
| 571 ASSERT(holder->HasNamedInterceptor()); |
| 572 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 628 | 573 |
| 629 void CompileCacheable(MacroAssembler* masm, | 574 // Check that the receiver isn't a smi. |
| 630 StubCompiler* stub_compiler, | 575 __ BranchOnSmi(receiver, miss); |
| 631 Register receiver, | |
| 632 Register holder, | |
| 633 Register scratch1, | |
| 634 Register scratch2, | |
| 635 JSObject* holder_obj, | |
| 636 LookupResult* lookup, | |
| 637 String* name, | |
| 638 Label* miss_label) { | |
| 639 JSFunction* function = 0; | |
| 640 bool optimize = false; | |
| 641 // So far the most popular case for failed interceptor is | |
| 642 // CONSTANT_FUNCTION sitting below. | |
| 643 if (lookup->type() == CONSTANT_FUNCTION) { | |
| 644 function = lookup->GetConstantFunction(); | |
| 645 // JSArray holder is a special case for call constant function | |
| 646 // (see the corresponding code). | |
| 647 if (function->is_compiled() && !holder_obj->IsJSArray()) { | |
| 648 optimize = true; | |
| 649 } | |
| 650 } | |
| 651 | 576 |
| 652 if (!optimize) { | 577 // Check that the maps haven't changed. |
| 653 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); | 578 Register reg = |
| 654 return; | 579 stub_compiler->CheckPrototypes(object, receiver, holder, |
| 655 } | 580 scratch1, scratch2, name, miss); |
| 656 | 581 |
| 657 // Constant functions cannot sit on global object. | 582 if (lookup->IsProperty() && lookup->IsCacheable()) { |
| 658 ASSERT(!lookup->holder()->IsGlobalObject()); | 583 compiler->CompileCacheable(masm, |
| 659 | 584 stub_compiler, |
| 660 __ EnterInternalFrame(); | 585 receiver, |
| 661 __ push(holder); // Save the holder. | 586 reg, |
| 662 __ push(name_); // Save the name. | 587 scratch1, |
| 663 | 588 scratch2, |
| 664 CompileCallLoadPropertyWithInterceptor(masm, | 589 holder, |
| 665 receiver, | 590 lookup, |
| 666 holder, | 591 name, |
| 667 name_, | 592 miss); |
| 668 holder_obj); | 593 } else { |
| 669 | 594 compiler->CompileRegular(masm, |
| 670 ASSERT(!r0.is(name_)); | 595 receiver, |
| 671 ASSERT(!r0.is(scratch1)); | 596 reg, |
| 672 __ pop(name_); // Restore the name. | 597 scratch2, |
| 673 __ pop(scratch1); // Restore the holder. | 598 holder, |
| 674 __ LeaveInternalFrame(); | 599 miss); |
| 675 | |
| 676 // Compare with no_interceptor_result_sentinel. | |
| 677 __ LoadRoot(scratch2, Heap::kNoInterceptorResultSentinelRootIndex); | |
| 678 __ cmp(r0, scratch2); | |
| 679 Label invoke; | |
| 680 __ b(ne, &invoke); | |
| 681 | |
| 682 stub_compiler->CheckPrototypes(holder_obj, scratch1, | |
| 683 lookup->holder(), scratch1, | |
| 684 scratch2, | |
| 685 name, | |
| 686 miss_label); | |
| 687 GenerateCallConstFunction(masm, function, arguments_); | |
| 688 | |
| 689 __ bind(&invoke); | |
| 690 } | 600 } |
| 691 | 601 } |
| 692 void CompileRegular(MacroAssembler* masm, | |
| 693 Register receiver, | |
| 694 Register holder, | |
| 695 Register scratch, | |
| 696 JSObject* holder_obj, | |
| 697 Label* miss_label) { | |
| 698 __ EnterInternalFrame(); | |
| 699 // Save the name_ register across the call. | |
| 700 __ push(name_); | |
| 701 | |
| 702 PushInterceptorArguments(masm, | |
| 703 receiver, | |
| 704 holder, | |
| 705 name_, | |
| 706 holder_obj); | |
| 707 | |
| 708 ExternalReference ref = ExternalReference( | |
| 709 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)); | |
| 710 __ mov(r0, Operand(5)); | |
| 711 __ mov(r1, Operand(ref)); | |
| 712 | |
| 713 CEntryStub stub(1); | |
| 714 __ CallStub(&stub); | |
| 715 | |
| 716 // Restore the name_ register. | |
| 717 __ pop(name_); | |
| 718 __ LeaveInternalFrame(); | |
| 719 } | |
| 720 | |
| 721 private: | |
| 722 const ParameterCount& arguments_; | |
| 723 int argc_; | |
| 724 Register name_; | |
| 725 }; | |
| 726 | 602 |
| 727 | 603 |
| 728 #undef __ | 604 #undef __ |
| 729 #define __ ACCESS_MASM(masm()) | 605 #define __ ACCESS_MASM(masm()) |
| 730 | 606 |
| 731 | 607 |
| 732 Register StubCompiler::CheckPrototypes(JSObject* object, | 608 Register StubCompiler::CheckPrototypes(JSObject* object, |
| 733 Register object_reg, | 609 Register object_reg, |
| 734 JSObject* holder, | 610 JSObject* holder, |
| 735 Register holder_reg, | 611 Register holder_reg, |
| 736 Register scratch, | 612 Register scratch, |
| 737 String* name, | 613 String* name, |
| 614 int save_at_depth, |
| 738 Label* miss) { | 615 Label* miss) { |
| 616 // TODO(602): support object saving. |
| 617 ASSERT(save_at_depth == kInvalidProtoDepth); |
| 618 |
| 739 // Check that the maps haven't changed. | 619 // Check that the maps haven't changed. |
| 740 Register result = | 620 Register result = |
| 741 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss); | 621 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss); |
| 742 | 622 |
| 743 // If we've skipped any global objects, it's not enough to verify | 623 // If we've skipped any global objects, it's not enough to verify |
| 744 // that their maps haven't changed. | 624 // that their maps haven't changed. |
| 745 while (object != holder) { | 625 while (object != holder) { |
| 746 if (object->IsGlobalObject()) { | 626 if (object->IsGlobalObject()) { |
| 747 GlobalObject* global = GlobalObject::cast(object); | 627 GlobalObject* global = GlobalObject::cast(object); |
| 748 Object* probe = global->EnsurePropertyCell(name); | 628 Object* probe = global->EnsurePropertyCell(name); |
| 749 if (probe->IsFailure()) { | 629 if (probe->IsFailure()) { |
| 750 set_failure(Failure::cast(probe)); | 630 set_failure(Failure::cast(probe)); |
| 751 return result; | 631 return result; |
| 752 } | 632 } |
| 753 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); | 633 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); |
| 754 ASSERT(cell->value()->IsTheHole()); | 634 ASSERT(cell->value()->IsTheHole()); |
| 755 __ mov(scratch, Operand(Handle<Object>(cell))); | 635 __ mov(scratch, Operand(Handle<Object>(cell))); |
| 756 __ ldr(scratch, | 636 __ ldr(scratch, |
| 757 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); | 637 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); |
| 758 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 638 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 759 __ cmp(scratch, ip); | 639 __ cmp(scratch, ip); |
| 760 __ b(ne, miss); | 640 __ b(ne, miss); |
| 761 } | 641 } |
| 762 object = JSObject::cast(object->GetPrototype()); | 642 object = JSObject::cast(object->GetPrototype()); |
| 763 } | 643 } |
| 764 | 644 |
| 765 // Return the register containin the holder. | 645 // Return the register containing the holder. |
| 766 return result; | 646 return result; |
| 767 } | 647 } |
| 768 | 648 |
| 769 | 649 |
| 770 void StubCompiler::GenerateLoadField(JSObject* object, | 650 void StubCompiler::GenerateLoadField(JSObject* object, |
| 771 JSObject* holder, | 651 JSObject* holder, |
| 772 Register receiver, | 652 Register receiver, |
| 773 Register scratch1, | 653 Register scratch1, |
| 774 Register scratch2, | 654 Register scratch2, |
| 775 int index, | 655 int index, |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 894 // Tear down temporary frame. | 774 // Tear down temporary frame. |
| 895 __ LeaveInternalFrame(); | 775 __ LeaveInternalFrame(); |
| 896 | 776 |
| 897 // Do a tail-call of the compiled function. | 777 // Do a tail-call of the compiled function. |
| 898 __ Jump(r2); | 778 __ Jump(r2); |
| 899 | 779 |
| 900 return GetCodeWithFlags(flags, "LazyCompileStub"); | 780 return GetCodeWithFlags(flags, "LazyCompileStub"); |
| 901 } | 781 } |
| 902 | 782 |
| 903 | 783 |
| 904 Object* CallStubCompiler::CompileCallField(Object* object, | 784 Object* CallStubCompiler::CompileCallField(JSObject* object, |
| 905 JSObject* holder, | 785 JSObject* holder, |
| 906 int index, | 786 int index, |
| 907 String* name) { | 787 String* name) { |
| 908 // ----------- S t a t e ------------- | 788 // ----------- S t a t e ------------- |
| 909 // -- lr: return address | 789 // -- r2 : name |
| 790 // -- lr : return address |
| 910 // ----------------------------------- | 791 // ----------------------------------- |
| 911 Label miss; | 792 Label miss; |
| 912 | 793 |
| 913 const int argc = arguments().immediate(); | 794 const int argc = arguments().immediate(); |
| 914 | 795 |
| 915 // Get the receiver of the function from the stack into r0. | 796 // Get the receiver of the function from the stack into r0. |
| 916 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); | 797 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); |
| 917 // Check that the receiver isn't a smi. | 798 // Check that the receiver isn't a smi. |
| 918 __ tst(r0, Operand(kSmiTagMask)); | 799 __ tst(r0, Operand(kSmiTagMask)); |
| 919 __ b(eq, &miss); | 800 __ b(eq, &miss); |
| 920 | 801 |
| 921 // Do the right check and compute the holder register. | 802 // Do the right check and compute the holder register. |
| 922 Register reg = | 803 Register reg = CheckPrototypes(object, r0, holder, r1, r3, name, &miss); |
| 923 CheckPrototypes(JSObject::cast(object), r0, holder, r3, r2, name, &miss); | |
| 924 GenerateFastPropertyLoad(masm(), r1, reg, holder, index); | 804 GenerateFastPropertyLoad(masm(), r1, reg, holder, index); |
| 925 | 805 |
| 926 GenerateCallFunction(masm(), object, arguments(), &miss); | 806 GenerateCallFunction(masm(), object, arguments(), &miss); |
| 927 | 807 |
| 928 // Handle call cache miss. | 808 // Handle call cache miss. |
| 929 __ bind(&miss); | 809 __ bind(&miss); |
| 930 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); | 810 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); |
| 931 __ Jump(ic, RelocInfo::CODE_TARGET); | 811 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 932 | 812 |
| 933 // Return the generated code. | 813 // Return the generated code. |
| 934 return GetCode(FIELD, name); | 814 return GetCode(FIELD, name); |
| 935 } | 815 } |
| 936 | 816 |
| 937 | 817 |
| 938 Object* CallStubCompiler::CompileCallConstant(Object* object, | 818 Object* CallStubCompiler::CompileCallConstant(Object* object, |
| 939 JSObject* holder, | 819 JSObject* holder, |
| 940 JSFunction* function, | 820 JSFunction* function, |
| 941 String* name, | 821 String* name, |
| 942 CheckType check) { | 822 CheckType check) { |
| 943 // ----------- S t a t e ------------- | 823 // ----------- S t a t e ------------- |
| 944 // -- lr: return address | 824 // -- r2 : name |
| 825 // -- lr : return address |
| 945 // ----------------------------------- | 826 // ----------------------------------- |
| 946 Label miss; | 827 Label miss; |
| 947 | 828 |
| 948 // Get the receiver from the stack | 829 // Get the receiver from the stack |
| 949 const int argc = arguments().immediate(); | 830 const int argc = arguments().immediate(); |
| 950 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | 831 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); |
| 951 | 832 |
| 952 // Check that the receiver isn't a smi. | 833 // Check that the receiver isn't a smi. |
| 953 if (check != NUMBER_CHECK) { | 834 if (check != NUMBER_CHECK) { |
| 954 __ tst(r1, Operand(kSmiTagMask)); | 835 __ tst(r1, Operand(kSmiTagMask)); |
| 955 __ b(eq, &miss); | 836 __ b(eq, &miss); |
| 956 } | 837 } |
| 957 | 838 |
| 958 // Make sure that it's okay not to patch the on stack receiver | 839 // Make sure that it's okay not to patch the on stack receiver |
| 959 // unless we're doing a receiver map check. | 840 // unless we're doing a receiver map check. |
| 960 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); | 841 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); |
| 961 | 842 |
| 962 switch (check) { | 843 switch (check) { |
| 963 case RECEIVER_MAP_CHECK: | 844 case RECEIVER_MAP_CHECK: |
| 964 // Check that the maps haven't changed. | 845 // Check that the maps haven't changed. |
| 965 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss); | 846 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss); |
| 966 | 847 |
| 967 // Patch the receiver on the stack with the global proxy if | 848 // Patch the receiver on the stack with the global proxy if |
| 968 // necessary. | 849 // necessary. |
| 969 if (object->IsGlobalObject()) { | 850 if (object->IsGlobalObject()) { |
| 970 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); | 851 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); |
| 971 __ str(r3, MemOperand(sp, argc * kPointerSize)); | 852 __ str(r3, MemOperand(sp, argc * kPointerSize)); |
| 972 } | 853 } |
| 973 break; | 854 break; |
| 974 | 855 |
| 975 case STRING_CHECK: | 856 case STRING_CHECK: |
| 976 if (!function->IsBuiltin()) { | 857 if (!function->IsBuiltin()) { |
| 977 // Calling non-builtins with a value as receiver requires boxing. | 858 // Calling non-builtins with a value as receiver requires boxing. |
| 978 __ jmp(&miss); | 859 __ jmp(&miss); |
| 979 } else { | 860 } else { |
| 980 // Check that the object is a two-byte string or a symbol. | 861 // Check that the object is a two-byte string or a symbol. |
| 981 __ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE); | 862 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE); |
| 982 __ b(hs, &miss); | 863 __ b(hs, &miss); |
| 983 // Check that the maps starting from the prototype haven't changed. | 864 // Check that the maps starting from the prototype haven't changed. |
| 984 GenerateLoadGlobalFunctionPrototype(masm(), | 865 GenerateLoadGlobalFunctionPrototype(masm(), |
| 985 Context::STRING_FUNCTION_INDEX, | 866 Context::STRING_FUNCTION_INDEX, |
| 986 r2); | 867 r0); |
| 987 CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3, | 868 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, |
| 988 r1, name, &miss); | 869 r1, name, &miss); |
| 989 } | 870 } |
| 990 break; | 871 break; |
| 991 | 872 |
| 992 case NUMBER_CHECK: { | 873 case NUMBER_CHECK: { |
| 993 if (!function->IsBuiltin()) { | 874 if (!function->IsBuiltin()) { |
| 994 // Calling non-builtins with a value as receiver requires boxing. | 875 // Calling non-builtins with a value as receiver requires boxing. |
| 995 __ jmp(&miss); | 876 __ jmp(&miss); |
| 996 } else { | 877 } else { |
| 997 Label fast; | 878 Label fast; |
| 998 // Check that the object is a smi or a heap number. | 879 // Check that the object is a smi or a heap number. |
| 999 __ tst(r1, Operand(kSmiTagMask)); | 880 __ tst(r1, Operand(kSmiTagMask)); |
| 1000 __ b(eq, &fast); | 881 __ b(eq, &fast); |
| 1001 __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE); | 882 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE); |
| 1002 __ b(ne, &miss); | 883 __ b(ne, &miss); |
| 1003 __ bind(&fast); | 884 __ bind(&fast); |
| 1004 // Check that the maps starting from the prototype haven't changed. | 885 // Check that the maps starting from the prototype haven't changed. |
| 1005 GenerateLoadGlobalFunctionPrototype(masm(), | 886 GenerateLoadGlobalFunctionPrototype(masm(), |
| 1006 Context::NUMBER_FUNCTION_INDEX, | 887 Context::NUMBER_FUNCTION_INDEX, |
| 1007 r2); | 888 r0); |
| 1008 CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3, | 889 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, |
| 1009 r1, name, &miss); | 890 r1, name, &miss); |
| 1010 } | 891 } |
| 1011 break; | 892 break; |
| 1012 } | 893 } |
| 1013 | 894 |
| 1014 case BOOLEAN_CHECK: { | 895 case BOOLEAN_CHECK: { |
| 1015 if (!function->IsBuiltin()) { | 896 if (!function->IsBuiltin()) { |
| 1016 // Calling non-builtins with a value as receiver requires boxing. | 897 // Calling non-builtins with a value as receiver requires boxing. |
| 1017 __ jmp(&miss); | 898 __ jmp(&miss); |
| 1018 } else { | 899 } else { |
| 1019 Label fast; | 900 Label fast; |
| 1020 // Check that the object is a boolean. | 901 // Check that the object is a boolean. |
| 1021 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 902 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| 1022 __ cmp(r1, ip); | 903 __ cmp(r1, ip); |
| 1023 __ b(eq, &fast); | 904 __ b(eq, &fast); |
| 1024 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 905 __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
| 1025 __ cmp(r1, ip); | 906 __ cmp(r1, ip); |
| 1026 __ b(ne, &miss); | 907 __ b(ne, &miss); |
| 1027 __ bind(&fast); | 908 __ bind(&fast); |
| 1028 // Check that the maps starting from the prototype haven't changed. | 909 // Check that the maps starting from the prototype haven't changed. |
| 1029 GenerateLoadGlobalFunctionPrototype(masm(), | 910 GenerateLoadGlobalFunctionPrototype(masm(), |
| 1030 Context::BOOLEAN_FUNCTION_INDEX, | 911 Context::BOOLEAN_FUNCTION_INDEX, |
| 1031 r2); | 912 r0); |
| 1032 CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3, | 913 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, |
| 1033 r1, name, &miss); | 914 r1, name, &miss); |
| 1034 } | 915 } |
| 1035 break; | 916 break; |
| 1036 } | 917 } |
| 1037 | 918 |
| 1038 case JSARRAY_HAS_FAST_ELEMENTS_CHECK: | 919 case JSARRAY_HAS_FAST_ELEMENTS_CHECK: |
| 1039 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss); | 920 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss); |
| 1040 // Make sure object->HasFastElements(). | 921 // Make sure object->HasFastElements(). |
| 1041 // Get the elements array of the object. | 922 // Get the elements array of the object. |
| 1042 __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset)); | 923 __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset)); |
| 1043 // Check that the object is in fast mode (not dictionary). | 924 // Check that the object is in fast mode (not dictionary). |
| 1044 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); | 925 __ ldr(r0, FieldMemOperand(r3, HeapObject::kMapOffset)); |
| 1045 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | 926 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
| 1046 __ cmp(r2, ip); | 927 __ cmp(r0, ip); |
| 1047 __ b(ne, &miss); | 928 __ b(ne, &miss); |
| 1048 break; | 929 break; |
| 1049 | 930 |
| 1050 default: | 931 default: |
| 1051 UNREACHABLE(); | 932 UNREACHABLE(); |
| 1052 } | 933 } |
| 1053 | 934 |
| 1054 GenerateCallConstFunction(masm(), function, arguments()); | 935 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); |
| 1055 | 936 |
| 1056 // Handle call cache miss. | 937 // Handle call cache miss. |
| 1057 __ bind(&miss); | 938 __ bind(&miss); |
| 1058 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); | 939 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); |
| 1059 __ Jump(ic, RelocInfo::CODE_TARGET); | 940 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 1060 | 941 |
| 1061 // Return the generated code. | 942 // Return the generated code. |
| 1062 String* function_name = NULL; | 943 String* function_name = NULL; |
| 1063 if (function->shared()->name()->IsString()) { | 944 if (function->shared()->name()->IsString()) { |
| 1064 function_name = String::cast(function->shared()->name()); | 945 function_name = String::cast(function->shared()->name()); |
| 1065 } | 946 } |
| 1066 return GetCode(CONSTANT_FUNCTION, function_name); | 947 return GetCode(CONSTANT_FUNCTION, function_name); |
| 1067 } | 948 } |
| 1068 | 949 |
| 1069 | 950 |
| 1070 Object* CallStubCompiler::CompileCallInterceptor(Object* object, | 951 Object* CallStubCompiler::CompileCallInterceptor(JSObject* object, |
| 1071 JSObject* holder, | 952 JSObject* holder, |
| 1072 String* name) { | 953 String* name) { |
| 1073 // ----------- S t a t e ------------- | 954 // ----------- S t a t e ------------- |
| 1074 // -- lr: return address | 955 // -- r2 : name |
| 956 // -- lr : return address |
| 1075 // ----------------------------------- | 957 // ----------------------------------- |
| 958 ASSERT(holder->HasNamedInterceptor()); |
| 959 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 1076 Label miss; | 960 Label miss; |
| 1077 | 961 |
| 962 const Register receiver = r0; |
| 963 const Register holder_reg = r1; |
| 964 const Register name_reg = r2; |
| 965 const Register scratch = r3; |
| 966 |
| 1078 // Get the number of arguments. | 967 // Get the number of arguments. |
| 1079 const int argc = arguments().immediate(); | 968 const int argc = arguments().immediate(); |
| 1080 | 969 |
| 1081 LookupResult lookup; | 970 LookupResult lookup; |
| 1082 LookupPostInterceptor(holder, name, &lookup); | 971 LookupPostInterceptor(holder, name, &lookup); |
| 1083 | 972 |
| 1084 // Get the receiver from the stack into r0. | 973 // Get the receiver from the stack into r0. |
| 1085 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); | 974 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); |
| 1086 // Load the name from the stack into r1. | |
| 1087 __ ldr(r1, MemOperand(sp, (argc + 1) * kPointerSize)); | |
| 1088 | 975 |
| 1089 CallInterceptorCompiler compiler(arguments(), r1); | 976 // Check that the receiver isn't a smi. |
| 1090 CompileLoadInterceptor(&compiler, | 977 __ BranchOnSmi(receiver, &miss); |
| 1091 this, | |
| 1092 masm(), | |
| 1093 JSObject::cast(object), | |
| 1094 holder, | |
| 1095 name, | |
| 1096 &lookup, | |
| 1097 r0, | |
| 1098 r2, | |
| 1099 r3, | |
| 1100 &miss); | |
| 1101 | 978 |
| 979 // Check that the maps haven't changed. |
| 980 Register reg = CheckPrototypes(object, receiver, holder, holder_reg, |
| 981 scratch, name, &miss); |
| 982 if (!reg.is(holder_reg)) { |
| 983 __ mov(holder_reg, reg); |
| 984 } |
| 985 |
| 986 // If we call a constant function when the interceptor returns |
| 987 // the no-result sentinel, generate code that optimizes this case. |
| 988 if (lookup.IsProperty() && |
| 989 lookup.IsCacheable() && |
| 990 lookup.type() == CONSTANT_FUNCTION && |
| 991 lookup.GetConstantFunction()->is_compiled() && |
| 992 !holder->IsJSArray()) { |
| 993 // Constant functions cannot sit on global object. |
| 994 ASSERT(!lookup.holder()->IsGlobalObject()); |
| 995 |
| 996 // Call the interceptor. |
| 997 __ EnterInternalFrame(); |
| 998 __ push(holder_reg); |
| 999 __ push(name_reg); |
| 1000 CompileCallLoadPropertyWithInterceptor(masm(), |
| 1001 receiver, |
| 1002 holder_reg, |
| 1003 name_reg, |
| 1004 holder); |
| 1005 __ pop(name_reg); |
| 1006 __ pop(holder_reg); |
| 1007 __ LeaveInternalFrame(); |
| 1008 // r0 no longer contains the receiver. |
| 1009 |
| 1010 // If interceptor returns no-result sentinal, call the constant function. |
| 1011 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex); |
| 1012 __ cmp(r0, scratch); |
| 1013 Label invoke; |
| 1014 __ b(ne, &invoke); |
| 1015 // Check the prototypes between the interceptor's holder and the |
| 1016 // constant function's holder. |
| 1017 CheckPrototypes(holder, holder_reg, |
| 1018 lookup.holder(), r0, |
| 1019 scratch, |
| 1020 name, |
| 1021 &miss); |
| 1022 |
| 1023 __ InvokeFunction(lookup.GetConstantFunction(), |
| 1024 arguments(), |
| 1025 JUMP_FUNCTION); |
| 1026 |
| 1027 __ bind(&invoke); |
| 1028 |
| 1029 } else { |
| 1030 // Call a runtime function to load the interceptor property. |
| 1031 __ EnterInternalFrame(); |
| 1032 __ push(name_reg); |
| 1033 |
| 1034 PushInterceptorArguments(masm(), receiver, holder_reg, name_reg, holder); |
| 1035 |
| 1036 __ CallExternalReference( |
| 1037 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall)), |
| 1038 5); |
| 1039 |
| 1040 __ pop(name_reg); |
| 1041 __ LeaveInternalFrame(); |
| 1042 } |
| 1043 |
| 1044 // Move returned value, the function to call, to r1. |
| 1045 __ mov(r1, r0); |
| 1102 // Restore receiver. | 1046 // Restore receiver. |
| 1103 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); | 1047 __ ldr(receiver, MemOperand(sp, argc * kPointerSize)); |
| 1104 | 1048 |
| 1105 GenerateCallFunction(masm(), object, arguments(), &miss); | 1049 GenerateCallFunction(masm(), object, arguments(), &miss); |
| 1106 | 1050 |
| 1107 // Handle call cache miss. | 1051 // Handle call cache miss. |
| 1108 __ bind(&miss); | 1052 __ bind(&miss); |
| 1109 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); | 1053 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); |
| 1110 __ Jump(ic, RelocInfo::CODE_TARGET); | 1054 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 1111 | 1055 |
| 1112 // Return the generated code. | 1056 // Return the generated code. |
| 1113 return GetCode(INTERCEPTOR, name); | 1057 return GetCode(INTERCEPTOR, name); |
| 1114 } | 1058 } |
| 1115 | 1059 |
| 1116 | 1060 |
| 1117 Object* CallStubCompiler::CompileCallGlobal(JSObject* object, | 1061 Object* CallStubCompiler::CompileCallGlobal(JSObject* object, |
| 1118 GlobalObject* holder, | 1062 GlobalObject* holder, |
| 1119 JSGlobalPropertyCell* cell, | 1063 JSGlobalPropertyCell* cell, |
| 1120 JSFunction* function, | 1064 JSFunction* function, |
| 1121 String* name) { | 1065 String* name) { |
| 1122 // ----------- S t a t e ------------- | 1066 // ----------- S t a t e ------------- |
| 1123 // -- lr: return address | 1067 // -- r2 : name |
| 1068 // -- lr : return address |
| 1124 // ----------------------------------- | 1069 // ----------------------------------- |
| 1125 Label miss; | 1070 Label miss; |
| 1126 | 1071 |
| 1127 // Get the number of arguments. | 1072 // Get the number of arguments. |
| 1128 const int argc = arguments().immediate(); | 1073 const int argc = arguments().immediate(); |
| 1129 | 1074 |
| 1130 // Get the receiver from the stack. | 1075 // Get the receiver from the stack. |
| 1131 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); | 1076 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); |
| 1132 | 1077 |
| 1133 // If the object is the holder then we know that it's a global | 1078 // If the object is the holder then we know that it's a global |
| 1134 // object which can only happen for contextual calls. In this case, | 1079 // object which can only happen for contextual calls. In this case, |
| 1135 // the receiver cannot be a smi. | 1080 // the receiver cannot be a smi. |
| 1136 if (object != holder) { | 1081 if (object != holder) { |
| 1137 __ tst(r0, Operand(kSmiTagMask)); | 1082 __ tst(r0, Operand(kSmiTagMask)); |
| 1138 __ b(eq, &miss); | 1083 __ b(eq, &miss); |
| 1139 } | 1084 } |
| 1140 | 1085 |
| 1141 // Check that the maps haven't changed. | 1086 // Check that the maps haven't changed. |
| 1142 CheckPrototypes(object, r0, holder, r3, r2, name, &miss); | 1087 CheckPrototypes(object, r0, holder, r3, r1, name, &miss); |
| 1143 | 1088 |
| 1144 // Get the value from the cell. | 1089 // Get the value from the cell. |
| 1145 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell))); | 1090 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell))); |
| 1146 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset)); | 1091 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset)); |
| 1147 | 1092 |
| 1148 // Check that the cell contains the same function. | 1093 // Check that the cell contains the same function. |
| 1149 if (Heap::InNewSpace(function)) { | 1094 if (Heap::InNewSpace(function)) { |
| 1150 // We can't embed a pointer to a function in new space so we have | 1095 // We can't embed a pointer to a function in new space so we have |
| 1151 // to verify that the shared function info is unchanged. This has | 1096 // to verify that the shared function info is unchanged. This has |
| 1152 // the nice side effect that multiple closures based on the same | 1097 // the nice side effect that multiple closures based on the same |
| 1153 // function can all use this call IC. Before we load through the | 1098 // function can all use this call IC. Before we load through the |
| 1154 // function, we have to verify that it still is a function. | 1099 // function, we have to verify that it still is a function. |
| 1155 __ tst(r1, Operand(kSmiTagMask)); | 1100 __ tst(r1, Operand(kSmiTagMask)); |
| 1156 __ b(eq, &miss); | 1101 __ b(eq, &miss); |
| 1157 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE); | 1102 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE); |
| 1158 __ b(ne, &miss); | 1103 __ b(ne, &miss); |
| 1159 | 1104 |
| 1160 // Check the shared function info. Make sure it hasn't changed. | 1105 // Check the shared function info. Make sure it hasn't changed. |
| 1161 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared()))); | 1106 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared()))); |
| 1162 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); | 1107 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); |
| 1163 __ cmp(r2, r3); | 1108 __ cmp(r4, r3); |
| 1164 __ b(ne, &miss); | 1109 __ b(ne, &miss); |
| 1165 } else { | 1110 } else { |
| 1166 __ cmp(r1, Operand(Handle<JSFunction>(function))); | 1111 __ cmp(r1, Operand(Handle<JSFunction>(function))); |
| 1167 __ b(ne, &miss); | 1112 __ b(ne, &miss); |
| 1168 } | 1113 } |
| 1169 | 1114 |
| 1170 // Patch the receiver on the stack with the global proxy if | 1115 // Patch the receiver on the stack with the global proxy if |
| 1171 // necessary. | 1116 // necessary. |
| 1172 if (object->IsGlobalObject()) { | 1117 if (object->IsGlobalObject()) { |
| 1173 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset)); | 1118 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset)); |
| 1174 __ str(r3, MemOperand(sp, argc * kPointerSize)); | 1119 __ str(r3, MemOperand(sp, argc * kPointerSize)); |
| 1175 } | 1120 } |
| 1176 | 1121 |
| 1177 // Setup the context (function already in r1). | 1122 // Setup the context (function already in r1). |
| 1178 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); | 1123 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); |
| 1179 | 1124 |
| 1180 // Jump to the cached code (tail call). | 1125 // Jump to the cached code (tail call). |
| 1181 __ IncrementCounter(&Counters::call_global_inline, 1, r2, r3); | 1126 __ IncrementCounter(&Counters::call_global_inline, 1, r1, r3); |
| 1182 ASSERT(function->is_compiled()); | 1127 ASSERT(function->is_compiled()); |
| 1183 Handle<Code> code(function->code()); | 1128 Handle<Code> code(function->code()); |
| 1184 ParameterCount expected(function->shared()->formal_parameter_count()); | 1129 ParameterCount expected(function->shared()->formal_parameter_count()); |
| 1185 __ InvokeCode(code, expected, arguments(), | 1130 __ InvokeCode(code, expected, arguments(), |
| 1186 RelocInfo::CODE_TARGET, JUMP_FUNCTION); | 1131 RelocInfo::CODE_TARGET, JUMP_FUNCTION); |
| 1187 | 1132 |
| 1188 // Handle call cache miss. | 1133 // Handle call cache miss. |
| 1189 __ bind(&miss); | 1134 __ bind(&miss); |
| 1190 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3); | 1135 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3); |
| 1191 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); | 1136 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); |
| 1192 __ Jump(ic, RelocInfo::CODE_TARGET); | 1137 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 1193 | 1138 |
| 1194 // Return the generated code. | 1139 // Return the generated code. |
| 1195 return GetCode(NORMAL, name); | 1140 return GetCode(NORMAL, name); |
| 1196 } | 1141 } |
| 1197 | 1142 |
| 1198 | 1143 |
| 1199 Object* StoreStubCompiler::CompileStoreField(JSObject* object, | 1144 Object* StoreStubCompiler::CompileStoreField(JSObject* object, |
| 1200 int index, | 1145 int index, |
| 1201 Map* transition, | 1146 Map* transition, |
| 1202 String* name) { | 1147 String* name) { |
| 1203 // ----------- S t a t e ------------- | 1148 // ----------- S t a t e ------------- |
| 1204 // -- r0 : value | 1149 // -- r0 : value |
| 1150 // -- r1 : receiver |
| 1205 // -- r2 : name | 1151 // -- r2 : name |
| 1206 // -- lr : return address | 1152 // -- lr : return address |
| 1207 // -- [sp] : receiver | |
| 1208 // ----------------------------------- | 1153 // ----------------------------------- |
| 1209 Label miss; | 1154 Label miss; |
| 1210 | 1155 |
| 1211 // Get the receiver from the stack. | |
| 1212 __ ldr(r3, MemOperand(sp, 0 * kPointerSize)); | |
| 1213 | |
| 1214 // name register might be clobbered. | |
| 1215 GenerateStoreField(masm(), | 1156 GenerateStoreField(masm(), |
| 1216 Builtins::StoreIC_ExtendStorage, | |
| 1217 object, | 1157 object, |
| 1218 index, | 1158 index, |
| 1219 transition, | 1159 transition, |
| 1220 r3, r2, r1, | 1160 r1, r2, r3, |
| 1221 &miss); | 1161 &miss); |
| 1222 __ bind(&miss); | 1162 __ bind(&miss); |
| 1223 __ mov(r2, Operand(Handle<String>(name))); // restore name | |
| 1224 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); | 1163 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); |
| 1225 __ Jump(ic, RelocInfo::CODE_TARGET); | 1164 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 1226 | 1165 |
| 1227 // Return the generated code. | 1166 // Return the generated code. |
| 1228 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); | 1167 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); |
| 1229 } | 1168 } |
| 1230 | 1169 |
| 1231 | 1170 |
| 1232 Object* StoreStubCompiler::CompileStoreCallback(JSObject* object, | 1171 Object* StoreStubCompiler::CompileStoreCallback(JSObject* object, |
| 1233 AccessorInfo* callback, | 1172 AccessorInfo* callback, |
| 1234 String* name) { | 1173 String* name) { |
| 1235 // ----------- S t a t e ------------- | 1174 // ----------- S t a t e ------------- |
| 1236 // -- r0 : value | 1175 // -- r0 : value |
| 1176 // -- r1 : receiver |
| 1237 // -- r2 : name | 1177 // -- r2 : name |
| 1238 // -- lr : return address | 1178 // -- lr : return address |
| 1239 // -- [sp] : receiver | |
| 1240 // ----------------------------------- | 1179 // ----------------------------------- |
| 1241 Label miss; | 1180 Label miss; |
| 1242 | 1181 |
| 1243 // Get the object from the stack. | |
| 1244 __ ldr(r3, MemOperand(sp, 0 * kPointerSize)); | |
| 1245 | |
| 1246 // Check that the object isn't a smi. | 1182 // Check that the object isn't a smi. |
| 1247 __ tst(r3, Operand(kSmiTagMask)); | 1183 __ tst(r1, Operand(kSmiTagMask)); |
| 1248 __ b(eq, &miss); | 1184 __ b(eq, &miss); |
| 1249 | 1185 |
| 1250 // Check that the map of the object hasn't changed. | 1186 // Check that the map of the object hasn't changed. |
| 1251 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset)); | 1187 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 1252 __ cmp(r1, Operand(Handle<Map>(object->map()))); | 1188 __ cmp(r3, Operand(Handle<Map>(object->map()))); |
| 1253 __ b(ne, &miss); | 1189 __ b(ne, &miss); |
| 1254 | 1190 |
| 1255 // Perform global security token check if needed. | 1191 // Perform global security token check if needed. |
| 1256 if (object->IsJSGlobalProxy()) { | 1192 if (object->IsJSGlobalProxy()) { |
| 1257 __ CheckAccessGlobalProxy(r3, r1, &miss); | 1193 __ CheckAccessGlobalProxy(r1, r3, &miss); |
| 1258 } | 1194 } |
| 1259 | 1195 |
| 1260 // Stub never generated for non-global objects that require access | 1196 // Stub never generated for non-global objects that require access |
| 1261 // checks. | 1197 // checks. |
| 1262 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 1198 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
| 1263 | 1199 |
| 1264 __ ldr(ip, MemOperand(sp)); // receiver | 1200 __ push(r1); // receiver |
| 1265 __ push(ip); | |
| 1266 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info | 1201 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info |
| 1267 __ push(ip); | 1202 __ stm(db_w, sp, ip.bit() | r2.bit() | r0.bit()); |
| 1268 __ push(r2); // name | |
| 1269 __ push(r0); // value | |
| 1270 | 1203 |
| 1271 // Do tail-call to the runtime system. | 1204 // Do tail-call to the runtime system. |
| 1272 ExternalReference store_callback_property = | 1205 ExternalReference store_callback_property = |
| 1273 ExternalReference(IC_Utility(IC::kStoreCallbackProperty)); | 1206 ExternalReference(IC_Utility(IC::kStoreCallbackProperty)); |
| 1274 __ TailCallRuntime(store_callback_property, 4, 1); | 1207 __ TailCallRuntime(store_callback_property, 4, 1); |
| 1275 | 1208 |
| 1276 // Handle store cache miss. | 1209 // Handle store cache miss. |
| 1277 __ bind(&miss); | 1210 __ bind(&miss); |
| 1278 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); | 1211 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); |
| 1279 __ Jump(ic, RelocInfo::CODE_TARGET); | 1212 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 1280 | 1213 |
| 1281 // Return the generated code. | 1214 // Return the generated code. |
| 1282 return GetCode(CALLBACKS, name); | 1215 return GetCode(CALLBACKS, name); |
| 1283 } | 1216 } |
| 1284 | 1217 |
| 1285 | 1218 |
| 1286 Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, | 1219 Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, |
| 1287 String* name) { | 1220 String* name) { |
| 1288 // ----------- S t a t e ------------- | 1221 // ----------- S t a t e ------------- |
| 1289 // -- r0 : value | 1222 // -- r0 : value |
| 1223 // -- r1 : receiver |
| 1290 // -- r2 : name | 1224 // -- r2 : name |
| 1291 // -- lr : return address | 1225 // -- lr : return address |
| 1292 // -- [sp] : receiver | |
| 1293 // ----------------------------------- | 1226 // ----------------------------------- |
| 1294 Label miss; | 1227 Label miss; |
| 1295 | 1228 |
| 1296 // Get the object from the stack. | |
| 1297 __ ldr(r3, MemOperand(sp, 0 * kPointerSize)); | |
| 1298 | |
| 1299 // Check that the object isn't a smi. | 1229 // Check that the object isn't a smi. |
| 1300 __ tst(r3, Operand(kSmiTagMask)); | 1230 __ tst(r1, Operand(kSmiTagMask)); |
| 1301 __ b(eq, &miss); | 1231 __ b(eq, &miss); |
| 1302 | 1232 |
| 1303 // Check that the map of the object hasn't changed. | 1233 // Check that the map of the object hasn't changed. |
| 1304 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset)); | 1234 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 1305 __ cmp(r1, Operand(Handle<Map>(receiver->map()))); | 1235 __ cmp(r3, Operand(Handle<Map>(receiver->map()))); |
| 1306 __ b(ne, &miss); | 1236 __ b(ne, &miss); |
| 1307 | 1237 |
| 1308 // Perform global security token check if needed. | 1238 // Perform global security token check if needed. |
| 1309 if (receiver->IsJSGlobalProxy()) { | 1239 if (receiver->IsJSGlobalProxy()) { |
| 1310 __ CheckAccessGlobalProxy(r3, r1, &miss); | 1240 __ CheckAccessGlobalProxy(r1, r3, &miss); |
| 1311 } | 1241 } |
| 1312 | 1242 |
| 1313 // Stub never generated for non-global objects that require access | 1243 // Stub is never generated for non-global objects that require access |
| 1314 // checks. | 1244 // checks. |
| 1315 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded()); | 1245 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded()); |
| 1316 | 1246 |
| 1317 __ ldr(ip, MemOperand(sp)); // receiver | 1247 __ push(r1); // receiver. |
| 1318 __ push(ip); | 1248 __ push(r2); // name. |
| 1319 __ push(r2); // name | 1249 __ push(r0); // value. |
| 1320 __ push(r0); // value | |
| 1321 | 1250 |
| 1322 // Do tail-call to the runtime system. | 1251 // Do tail-call to the runtime system. |
| 1323 ExternalReference store_ic_property = | 1252 ExternalReference store_ic_property = |
| 1324 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); | 1253 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); |
| 1325 __ TailCallRuntime(store_ic_property, 3, 1); | 1254 __ TailCallRuntime(store_ic_property, 3, 1); |
| 1326 | 1255 |
| 1327 // Handle store cache miss. | 1256 // Handle store cache miss. |
| 1328 __ bind(&miss); | 1257 __ bind(&miss); |
| 1329 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); | 1258 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); |
| 1330 __ Jump(ic, RelocInfo::CODE_TARGET); | 1259 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 1331 | 1260 |
| 1332 // Return the generated code. | 1261 // Return the generated code. |
| 1333 return GetCode(INTERCEPTOR, name); | 1262 return GetCode(INTERCEPTOR, name); |
| 1334 } | 1263 } |
| 1335 | 1264 |
| 1336 | 1265 |
| 1337 Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, | 1266 Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, |
| 1338 JSGlobalPropertyCell* cell, | 1267 JSGlobalPropertyCell* cell, |
| 1339 String* name) { | 1268 String* name) { |
| 1340 // ----------- S t a t e ------------- | 1269 // ----------- S t a t e ------------- |
| 1341 // -- r0 : value | 1270 // -- r0 : value |
| 1271 // -- r1 : receiver |
| 1342 // -- r2 : name | 1272 // -- r2 : name |
| 1343 // -- lr : return address | 1273 // -- lr : return address |
| 1344 // -- [sp] : receiver | |
| 1345 // ----------------------------------- | 1274 // ----------------------------------- |
| 1346 Label miss; | 1275 Label miss; |
| 1347 | 1276 |
| 1348 // Check that the map of the global has not changed. | 1277 // Check that the map of the global has not changed. |
| 1349 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); | |
| 1350 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); | 1278 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 1351 __ cmp(r3, Operand(Handle<Map>(object->map()))); | 1279 __ cmp(r3, Operand(Handle<Map>(object->map()))); |
| 1352 __ b(ne, &miss); | 1280 __ b(ne, &miss); |
| 1353 | 1281 |
| 1354 // Store the value in the cell. | 1282 // Store the value in the cell. |
| 1355 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell))); | 1283 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell))); |
| 1356 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset)); | 1284 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset)); |
| 1357 | 1285 |
| 1358 __ IncrementCounter(&Counters::named_store_global_inline, 1, r1, r3); | 1286 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3); |
| 1359 __ Ret(); | 1287 __ Ret(); |
| 1360 | 1288 |
| 1361 // Handle store cache miss. | 1289 // Handle store cache miss. |
| 1362 __ bind(&miss); | 1290 __ bind(&miss); |
| 1363 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r1, r3); | 1291 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3); |
| 1364 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); | 1292 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); |
| 1365 __ Jump(ic, RelocInfo::CODE_TARGET); | 1293 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 1366 | 1294 |
| 1367 // Return the generated code. | 1295 // Return the generated code. |
| 1368 return GetCode(NORMAL, name); | 1296 return GetCode(NORMAL, name); |
| 1369 } | 1297 } |
| 1370 | 1298 |
| 1371 | 1299 |
| 1372 Object* LoadStubCompiler::CompileLoadField(JSObject* object, | 1300 Object* LoadStubCompiler::CompileLoadField(JSObject* object, |
| 1373 JSObject* holder, | 1301 JSObject* holder, |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1665 // ----------------------------------- | 1593 // ----------------------------------- |
| 1666 Label miss; | 1594 Label miss; |
| 1667 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3); | 1595 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3); |
| 1668 | 1596 |
| 1669 __ ldr(r2, MemOperand(sp)); | 1597 __ ldr(r2, MemOperand(sp)); |
| 1670 __ ldr(r0, MemOperand(sp, kPointerSize)); // receiver | 1598 __ ldr(r0, MemOperand(sp, kPointerSize)); // receiver |
| 1671 | 1599 |
| 1672 __ cmp(r2, Operand(Handle<String>(name))); | 1600 __ cmp(r2, Operand(Handle<String>(name))); |
| 1673 __ b(ne, &miss); | 1601 __ b(ne, &miss); |
| 1674 | 1602 |
| 1675 GenerateLoadStringLength2(masm(), r0, r1, r3, &miss); | 1603 GenerateLoadStringLength(masm(), r0, r1, r3, &miss); |
| 1676 __ bind(&miss); | 1604 __ bind(&miss); |
| 1677 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3); | 1605 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3); |
| 1678 | 1606 |
| 1679 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 1607 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 1680 | 1608 |
| 1681 return GetCode(CALLBACKS, name); | 1609 return GetCode(CALLBACKS, name); |
| 1682 } | 1610 } |
| 1683 | 1611 |
| 1684 | 1612 |
| 1685 // TODO(1224671): implement the fast case. | 1613 // TODO(1224671): implement the fast case. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1710 __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3); | 1638 __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3); |
| 1711 | 1639 |
| 1712 // Check that the name has not changed. | 1640 // Check that the name has not changed. |
| 1713 __ cmp(r2, Operand(Handle<String>(name))); | 1641 __ cmp(r2, Operand(Handle<String>(name))); |
| 1714 __ b(ne, &miss); | 1642 __ b(ne, &miss); |
| 1715 | 1643 |
| 1716 // Load receiver from the stack. | 1644 // Load receiver from the stack. |
| 1717 __ ldr(r3, MemOperand(sp)); | 1645 __ ldr(r3, MemOperand(sp)); |
| 1718 // r1 is used as scratch register, r3 and r2 might be clobbered. | 1646 // r1 is used as scratch register, r3 and r2 might be clobbered. |
| 1719 GenerateStoreField(masm(), | 1647 GenerateStoreField(masm(), |
| 1720 Builtins::StoreIC_ExtendStorage, | |
| 1721 object, | 1648 object, |
| 1722 index, | 1649 index, |
| 1723 transition, | 1650 transition, |
| 1724 r3, r2, r1, | 1651 r3, r2, r1, |
| 1725 &miss); | 1652 &miss); |
| 1726 __ bind(&miss); | 1653 __ bind(&miss); |
| 1727 | 1654 |
| 1728 __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3); | 1655 __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3); |
| 1729 __ mov(r2, Operand(Handle<String>(name))); // restore name register. | 1656 __ mov(r2, Operand(Handle<String>(name))); // restore name register. |
| 1730 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); | 1657 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1874 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); | 1801 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); |
| 1875 | 1802 |
| 1876 // Return the generated code. | 1803 // Return the generated code. |
| 1877 return GetCode(); | 1804 return GetCode(); |
| 1878 } | 1805 } |
| 1879 | 1806 |
| 1880 | 1807 |
| 1881 #undef __ | 1808 #undef __ |
| 1882 | 1809 |
| 1883 } } // namespace v8::internal | 1810 } } // namespace v8::internal |
| OLD | NEW |