| 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 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 | 122 |
| 123 const int kInterceptorOrAccessCheckNeededMask = | 123 const int kInterceptorOrAccessCheckNeededMask = |
| 124 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); | 124 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); |
| 125 | 125 |
| 126 // Bail out if the receiver has a named interceptor or requires access checks. | 126 // Bail out if the receiver has a named interceptor or requires access checks. |
| 127 __ test_b(FieldOperand(r0, Map::kBitFieldOffset), | 127 __ test_b(FieldOperand(r0, Map::kBitFieldOffset), |
| 128 kInterceptorOrAccessCheckNeededMask); | 128 kInterceptorOrAccessCheckNeededMask); |
| 129 __ j(not_zero, miss_label); | 129 __ j(not_zero, miss_label); |
| 130 | 130 |
| 131 // Check that receiver is a JSObject. | 131 // Check that receiver is a JSObject. |
| 132 __ CmpInstanceType(r0, FIRST_JS_OBJECT_TYPE); | 132 __ CmpInstanceType(r0, FIRST_SPEC_OBJECT_TYPE); |
| 133 __ j(below, miss_label); | 133 __ j(below, miss_label); |
| 134 | 134 |
| 135 // Load properties array. | 135 // Load properties array. |
| 136 Register properties = r0; | 136 Register properties = r0; |
| 137 __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset)); | 137 __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset)); |
| 138 | 138 |
| 139 // Check that the properties array is a dictionary. | 139 // Check that the properties array is a dictionary. |
| 140 __ cmp(FieldOperand(properties, HeapObject::kMapOffset), | 140 __ cmp(FieldOperand(properties, HeapObject::kMapOffset), |
| 141 Immediate(masm->isolate()->factory()->hash_table_map())); | 141 Immediate(masm->isolate()->factory()->hash_table_map())); |
| 142 __ j(not_equal, miss_label); | 142 __ j(not_equal, miss_label); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 ASSERT(!scratch.is(name)); | 181 ASSERT(!scratch.is(name)); |
| 182 ASSERT(!extra.is(receiver)); | 182 ASSERT(!extra.is(receiver)); |
| 183 ASSERT(!extra.is(name)); | 183 ASSERT(!extra.is(name)); |
| 184 ASSERT(!extra.is(scratch)); | 184 ASSERT(!extra.is(scratch)); |
| 185 | 185 |
| 186 // Check scratch and extra registers are valid, and extra2 is unused. | 186 // Check scratch and extra registers are valid, and extra2 is unused. |
| 187 ASSERT(!scratch.is(no_reg)); | 187 ASSERT(!scratch.is(no_reg)); |
| 188 ASSERT(extra2.is(no_reg)); | 188 ASSERT(extra2.is(no_reg)); |
| 189 | 189 |
| 190 // Check that the receiver isn't a smi. | 190 // Check that the receiver isn't a smi. |
| 191 __ test(receiver, Immediate(kSmiTagMask)); | 191 __ JumpIfSmi(receiver, &miss); |
| 192 __ j(zero, &miss); | |
| 193 | 192 |
| 194 // Get the map of the receiver and compute the hash. | 193 // Get the map of the receiver and compute the hash. |
| 195 __ mov(scratch, FieldOperand(name, String::kHashFieldOffset)); | 194 __ mov(scratch, FieldOperand(name, String::kHashFieldOffset)); |
| 196 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); | 195 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 197 __ xor_(scratch, flags); | 196 __ xor_(scratch, flags); |
| 198 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize); | 197 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize); |
| 199 | 198 |
| 200 // Probe the primary table. | 199 // Probe the primary table. |
| 201 ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra); | 200 ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra); |
| 202 | 201 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 // Load the prototype from the initial map. | 241 // Load the prototype from the initial map. |
| 243 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); | 242 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); |
| 244 } | 243 } |
| 245 | 244 |
| 246 | 245 |
| 247 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, | 246 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, |
| 248 Register receiver, | 247 Register receiver, |
| 249 Register scratch, | 248 Register scratch, |
| 250 Label* miss_label) { | 249 Label* miss_label) { |
| 251 // Check that the receiver isn't a smi. | 250 // Check that the receiver isn't a smi. |
| 252 __ test(receiver, Immediate(kSmiTagMask)); | 251 __ JumpIfSmi(receiver, miss_label); |
| 253 __ j(zero, miss_label); | |
| 254 | 252 |
| 255 // Check that the object is a JS array. | 253 // Check that the object is a JS array. |
| 256 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); | 254 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); |
| 257 __ j(not_equal, miss_label); | 255 __ j(not_equal, miss_label); |
| 258 | 256 |
| 259 // Load length directly from the JS array. | 257 // Load length directly from the JS array. |
| 260 __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset)); | 258 __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset)); |
| 261 __ ret(0); | 259 __ ret(0); |
| 262 } | 260 } |
| 263 | 261 |
| 264 | 262 |
| 265 // Generate code to check if an object is a string. If the object is | 263 // Generate code to check if an object is a string. If the object is |
| 266 // a string, the map's instance type is left in the scratch register. | 264 // a string, the map's instance type is left in the scratch register. |
| 267 static void GenerateStringCheck(MacroAssembler* masm, | 265 static void GenerateStringCheck(MacroAssembler* masm, |
| 268 Register receiver, | 266 Register receiver, |
| 269 Register scratch, | 267 Register scratch, |
| 270 Label* smi, | 268 Label* smi, |
| 271 Label* non_string_object) { | 269 Label* non_string_object) { |
| 272 // Check that the object isn't a smi. | 270 // Check that the object isn't a smi. |
| 273 __ test(receiver, Immediate(kSmiTagMask)); | 271 __ JumpIfSmi(receiver, smi); |
| 274 __ j(zero, smi); | |
| 275 | 272 |
| 276 // Check that the object is a string. | 273 // Check that the object is a string. |
| 277 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); | 274 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 278 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 275 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 279 ASSERT(kNotStringTag != 0); | 276 ASSERT(kNotStringTag != 0); |
| 280 __ test(scratch, Immediate(kNotStringTag)); | 277 __ test(scratch, Immediate(kNotStringTag)); |
| 281 __ j(not_zero, non_string_object); | 278 __ j(not_zero, non_string_object); |
| 282 } | 279 } |
| 283 | 280 |
| 284 | 281 |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 Object* callback = optimization.api_call_info()->callback(); | 452 Object* callback = optimization.api_call_info()->callback(); |
| 456 Address api_function_address = v8::ToCData<Address>(callback); | 453 Address api_function_address = v8::ToCData<Address>(callback); |
| 457 ApiFunction fun(api_function_address); | 454 ApiFunction fun(api_function_address); |
| 458 | 455 |
| 459 const int kApiArgc = 1; // API function gets reference to the v8::Arguments. | 456 const int kApiArgc = 1; // API function gets reference to the v8::Arguments. |
| 460 | 457 |
| 461 // Allocate the v8::Arguments structure in the arguments' space since | 458 // Allocate the v8::Arguments structure in the arguments' space since |
| 462 // it's not controlled by GC. | 459 // it's not controlled by GC. |
| 463 const int kApiStackSpace = 4; | 460 const int kApiStackSpace = 4; |
| 464 | 461 |
| 465 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace, ebx); | 462 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace); |
| 466 | 463 |
| 467 __ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_. | 464 __ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_. |
| 468 __ add(Operand(eax), Immediate(argc * kPointerSize)); | 465 __ add(Operand(eax), Immediate(argc * kPointerSize)); |
| 469 __ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_. | 466 __ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_. |
| 470 __ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_. | 467 __ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_. |
| 471 // v8::Arguments::is_construct_call_. | 468 // v8::Arguments::is_construct_call_. |
| 472 __ Set(ApiParameterOperand(4), Immediate(0)); | 469 __ Set(ApiParameterOperand(4), Immediate(0)); |
| 473 | 470 |
| 474 // v8::InvocationCallback's argument. | 471 // v8::InvocationCallback's argument. |
| 475 __ lea(eax, ApiParameterOperand(1)); | 472 __ lea(eax, ApiParameterOperand(1)); |
| 476 __ mov(ApiParameterOperand(0), eax); | 473 __ mov(ApiParameterOperand(0), eax); |
| 477 | 474 |
| 478 // Emitting a stub call may try to allocate (if the code is not | 475 // Emitting a stub call may try to allocate (if the code is not |
| 479 // already generated). Do not allow the assembler to perform a | 476 // already generated). Do not allow the assembler to perform a |
| 480 // garbage collection but instead return the allocation failure | 477 // garbage collection but instead return the allocation failure |
| 481 // object. | 478 // object. |
| 482 return masm->TryCallApiFunctionAndReturn(&fun, | 479 return masm->TryCallApiFunctionAndReturn(&fun, |
| 483 argc + kFastApiCallArguments + 1); | 480 argc + kFastApiCallArguments + 1); |
| 484 } | 481 } |
| 485 | 482 |
| 486 | 483 |
| 487 class CallInterceptorCompiler BASE_EMBEDDED { | 484 class CallInterceptorCompiler BASE_EMBEDDED { |
| 488 public: | 485 public: |
| 489 CallInterceptorCompiler(StubCompiler* stub_compiler, | 486 CallInterceptorCompiler(StubCompiler* stub_compiler, |
| 490 const ParameterCount& arguments, | 487 const ParameterCount& arguments, |
| 491 Register name) | 488 Register name, |
| 489 Code::ExtraICState extra_ic_state) |
| 492 : stub_compiler_(stub_compiler), | 490 : stub_compiler_(stub_compiler), |
| 493 arguments_(arguments), | 491 arguments_(arguments), |
| 494 name_(name) {} | 492 name_(name), |
| 493 extra_ic_state_(extra_ic_state) {} |
| 495 | 494 |
| 496 MaybeObject* Compile(MacroAssembler* masm, | 495 MaybeObject* Compile(MacroAssembler* masm, |
| 497 JSObject* object, | 496 JSObject* object, |
| 498 JSObject* holder, | 497 JSObject* holder, |
| 499 String* name, | 498 String* name, |
| 500 LookupResult* lookup, | 499 LookupResult* lookup, |
| 501 Register receiver, | 500 Register receiver, |
| 502 Register scratch1, | 501 Register scratch1, |
| 503 Register scratch2, | 502 Register scratch2, |
| 504 Register scratch3, | 503 Register scratch3, |
| 505 Label* miss) { | 504 Label* miss) { |
| 506 ASSERT(holder->HasNamedInterceptor()); | 505 ASSERT(holder->HasNamedInterceptor()); |
| 507 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | 506 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 508 | 507 |
| 509 // Check that the receiver isn't a smi. | 508 // Check that the receiver isn't a smi. |
| 510 __ test(receiver, Immediate(kSmiTagMask)); | 509 __ JumpIfSmi(receiver, miss); |
| 511 __ j(zero, miss); | |
| 512 | 510 |
| 513 CallOptimization optimization(lookup); | 511 CallOptimization optimization(lookup); |
| 514 | 512 |
| 515 if (optimization.is_constant_call()) { | 513 if (optimization.is_constant_call()) { |
| 516 return CompileCacheable(masm, | 514 return CompileCacheable(masm, |
| 517 object, | 515 object, |
| 518 receiver, | 516 receiver, |
| 519 scratch1, | 517 scratch1, |
| 520 scratch2, | 518 scratch2, |
| 521 scratch3, | 519 scratch3, |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 609 // by the previous CheckPrototypes. | 607 // by the previous CheckPrototypes. |
| 610 ASSERT(depth2 == kInvalidProtoDepth); | 608 ASSERT(depth2 == kInvalidProtoDepth); |
| 611 } | 609 } |
| 612 | 610 |
| 613 // Invoke function. | 611 // Invoke function. |
| 614 if (can_do_fast_api_call) { | 612 if (can_do_fast_api_call) { |
| 615 MaybeObject* result = | 613 MaybeObject* result = |
| 616 GenerateFastApiCall(masm, optimization, arguments_.immediate()); | 614 GenerateFastApiCall(masm, optimization, arguments_.immediate()); |
| 617 if (result->IsFailure()) return result; | 615 if (result->IsFailure()) return result; |
| 618 } else { | 616 } else { |
| 617 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) |
| 618 ? CALL_AS_FUNCTION |
| 619 : CALL_AS_METHOD; |
| 619 __ InvokeFunction(optimization.constant_function(), arguments_, | 620 __ InvokeFunction(optimization.constant_function(), arguments_, |
| 620 JUMP_FUNCTION); | 621 JUMP_FUNCTION, NullCallWrapper(), call_kind); |
| 621 } | 622 } |
| 622 | 623 |
| 623 // Deferred code for fast API call case---clean preallocated space. | 624 // Deferred code for fast API call case---clean preallocated space. |
| 624 if (can_do_fast_api_call) { | 625 if (can_do_fast_api_call) { |
| 625 __ bind(&miss_cleanup); | 626 __ bind(&miss_cleanup); |
| 626 FreeSpaceForFastApiCall(masm, scratch1); | 627 FreeSpaceForFastApiCall(masm, scratch1); |
| 627 __ jmp(miss_label); | 628 __ jmp(miss_label); |
| 628 } | 629 } |
| 629 | 630 |
| 630 // Invoke a regular function. | 631 // Invoke a regular function. |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 689 __ pop(receiver); // Restore the holder. | 690 __ pop(receiver); // Restore the holder. |
| 690 __ LeaveInternalFrame(); | 691 __ LeaveInternalFrame(); |
| 691 | 692 |
| 692 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel()); | 693 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel()); |
| 693 __ j(not_equal, interceptor_succeeded); | 694 __ j(not_equal, interceptor_succeeded); |
| 694 } | 695 } |
| 695 | 696 |
| 696 StubCompiler* stub_compiler_; | 697 StubCompiler* stub_compiler_; |
| 697 const ParameterCount& arguments_; | 698 const ParameterCount& arguments_; |
| 698 Register name_; | 699 Register name_; |
| 700 Code::ExtraICState extra_ic_state_; |
| 699 }; | 701 }; |
| 700 | 702 |
| 701 | 703 |
| 702 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { | 704 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { |
| 703 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); | 705 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); |
| 704 Code* code = NULL; | 706 Code* code = NULL; |
| 705 if (kind == Code::LOAD_IC) { | 707 if (kind == Code::LOAD_IC) { |
| 706 code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss); | 708 code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss); |
| 707 } else { | 709 } else { |
| 708 code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss); | 710 code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 725 // but may be destroyed if store is successful. | 727 // but may be destroyed if store is successful. |
| 726 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | 728 void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
| 727 JSObject* object, | 729 JSObject* object, |
| 728 int index, | 730 int index, |
| 729 Map* transition, | 731 Map* transition, |
| 730 Register receiver_reg, | 732 Register receiver_reg, |
| 731 Register name_reg, | 733 Register name_reg, |
| 732 Register scratch, | 734 Register scratch, |
| 733 Label* miss_label) { | 735 Label* miss_label) { |
| 734 // Check that the object isn't a smi. | 736 // Check that the object isn't a smi. |
| 735 __ test(receiver_reg, Immediate(kSmiTagMask)); | 737 __ JumpIfSmi(receiver_reg, miss_label); |
| 736 __ j(zero, miss_label); | |
| 737 | 738 |
| 738 // Check that the map of the object hasn't changed. | 739 // Check that the map of the object hasn't changed. |
| 739 __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset), | 740 __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset), |
| 740 Immediate(Handle<Map>(object->map()))); | 741 Immediate(Handle<Map>(object->map()))); |
| 741 __ j(not_equal, miss_label); | 742 __ j(not_equal, miss_label); |
| 742 | 743 |
| 743 // Perform global security token check if needed. | 744 // Perform global security token check if needed. |
| 744 if (object->IsJSGlobalProxy()) { | 745 if (object->IsJSGlobalProxy()) { |
| 745 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label); | 746 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label); |
| 746 } | 747 } |
| (...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1015 void StubCompiler::GenerateLoadField(JSObject* object, | 1016 void StubCompiler::GenerateLoadField(JSObject* object, |
| 1016 JSObject* holder, | 1017 JSObject* holder, |
| 1017 Register receiver, | 1018 Register receiver, |
| 1018 Register scratch1, | 1019 Register scratch1, |
| 1019 Register scratch2, | 1020 Register scratch2, |
| 1020 Register scratch3, | 1021 Register scratch3, |
| 1021 int index, | 1022 int index, |
| 1022 String* name, | 1023 String* name, |
| 1023 Label* miss) { | 1024 Label* miss) { |
| 1024 // Check that the receiver isn't a smi. | 1025 // Check that the receiver isn't a smi. |
| 1025 __ test(receiver, Immediate(kSmiTagMask)); | 1026 __ JumpIfSmi(receiver, miss); |
| 1026 __ j(zero, miss); | |
| 1027 | 1027 |
| 1028 // Check the prototype chain. | 1028 // Check the prototype chain. |
| 1029 Register reg = | 1029 Register reg = |
| 1030 CheckPrototypes(object, receiver, holder, | 1030 CheckPrototypes(object, receiver, holder, |
| 1031 scratch1, scratch2, scratch3, name, miss); | 1031 scratch1, scratch2, scratch3, name, miss); |
| 1032 | 1032 |
| 1033 // Get the value from the properties. | 1033 // Get the value from the properties. |
| 1034 GenerateFastPropertyLoad(masm(), eax, reg, holder, index); | 1034 GenerateFastPropertyLoad(masm(), eax, reg, holder, index); |
| 1035 __ ret(0); | 1035 __ ret(0); |
| 1036 } | 1036 } |
| 1037 | 1037 |
| 1038 | 1038 |
| 1039 MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, | 1039 MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, |
| 1040 JSObject* holder, | 1040 JSObject* holder, |
| 1041 Register receiver, | 1041 Register receiver, |
| 1042 Register name_reg, | 1042 Register name_reg, |
| 1043 Register scratch1, | 1043 Register scratch1, |
| 1044 Register scratch2, | 1044 Register scratch2, |
| 1045 Register scratch3, | 1045 Register scratch3, |
| 1046 AccessorInfo* callback, | 1046 AccessorInfo* callback, |
| 1047 String* name, | 1047 String* name, |
| 1048 Label* miss) { | 1048 Label* miss) { |
| 1049 // Check that the receiver isn't a smi. | 1049 // Check that the receiver isn't a smi. |
| 1050 __ test(receiver, Immediate(kSmiTagMask)); | 1050 __ JumpIfSmi(receiver, miss); |
| 1051 __ j(zero, miss); | |
| 1052 | 1051 |
| 1053 // Check that the maps haven't changed. | 1052 // Check that the maps haven't changed. |
| 1054 Register reg = | 1053 Register reg = |
| 1055 CheckPrototypes(object, receiver, holder, scratch1, | 1054 CheckPrototypes(object, receiver, holder, scratch1, |
| 1056 scratch2, scratch3, name, miss); | 1055 scratch2, scratch3, name, miss); |
| 1057 | 1056 |
| 1058 Handle<AccessorInfo> callback_handle(callback); | 1057 Handle<AccessorInfo> callback_handle(callback); |
| 1059 | 1058 |
| 1060 // Insert additional parameters into the stack frame above return address. | 1059 // Insert additional parameters into the stack frame above return address. |
| 1061 ASSERT(!scratch3.is(reg)); | 1060 ASSERT(!scratch3.is(reg)); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1084 | 1083 |
| 1085 // Do call through the api. | 1084 // Do call through the api. |
| 1086 Address getter_address = v8::ToCData<Address>(callback->getter()); | 1085 Address getter_address = v8::ToCData<Address>(callback->getter()); |
| 1087 ApiFunction fun(getter_address); | 1086 ApiFunction fun(getter_address); |
| 1088 | 1087 |
| 1089 // 3 elements array for v8::Agruments::values_, handler for name and pointer | 1088 // 3 elements array for v8::Agruments::values_, handler for name and pointer |
| 1090 // to the values (it considered as smi in GC). | 1089 // to the values (it considered as smi in GC). |
| 1091 const int kStackSpace = 5; | 1090 const int kStackSpace = 5; |
| 1092 const int kApiArgc = 2; | 1091 const int kApiArgc = 2; |
| 1093 | 1092 |
| 1094 __ PrepareCallApiFunction(kApiArgc, eax); | 1093 __ PrepareCallApiFunction(kApiArgc); |
| 1095 __ mov(ApiParameterOperand(0), ebx); // name. | 1094 __ mov(ApiParameterOperand(0), ebx); // name. |
| 1096 __ add(Operand(ebx), Immediate(kPointerSize)); | 1095 __ add(Operand(ebx), Immediate(kPointerSize)); |
| 1097 __ mov(ApiParameterOperand(1), ebx); // arguments pointer. | 1096 __ mov(ApiParameterOperand(1), ebx); // arguments pointer. |
| 1098 | 1097 |
| 1099 // Emitting a stub call may try to allocate (if the code is not | 1098 // Emitting a stub call may try to allocate (if the code is not |
| 1100 // already generated). Do not allow the assembler to perform a | 1099 // already generated). Do not allow the assembler to perform a |
| 1101 // garbage collection but instead return the allocation failure | 1100 // garbage collection but instead return the allocation failure |
| 1102 // object. | 1101 // object. |
| 1103 return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); | 1102 return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); |
| 1104 } | 1103 } |
| 1105 | 1104 |
| 1106 | 1105 |
| 1107 void StubCompiler::GenerateLoadConstant(JSObject* object, | 1106 void StubCompiler::GenerateLoadConstant(JSObject* object, |
| 1108 JSObject* holder, | 1107 JSObject* holder, |
| 1109 Register receiver, | 1108 Register receiver, |
| 1110 Register scratch1, | 1109 Register scratch1, |
| 1111 Register scratch2, | 1110 Register scratch2, |
| 1112 Register scratch3, | 1111 Register scratch3, |
| 1113 Object* value, | 1112 Object* value, |
| 1114 String* name, | 1113 String* name, |
| 1115 Label* miss) { | 1114 Label* miss) { |
| 1116 // Check that the receiver isn't a smi. | 1115 // Check that the receiver isn't a smi. |
| 1117 __ test(receiver, Immediate(kSmiTagMask)); | 1116 __ JumpIfSmi(receiver, miss); |
| 1118 __ j(zero, miss); | |
| 1119 | 1117 |
| 1120 // Check that the maps haven't changed. | 1118 // Check that the maps haven't changed. |
| 1121 CheckPrototypes(object, receiver, holder, | 1119 CheckPrototypes(object, receiver, holder, |
| 1122 scratch1, scratch2, scratch3, name, miss); | 1120 scratch1, scratch2, scratch3, name, miss); |
| 1123 | 1121 |
| 1124 // Return the constant value. | 1122 // Return the constant value. |
| 1125 __ mov(eax, Handle<Object>(value)); | 1123 __ mov(eax, Handle<Object>(value)); |
| 1126 __ ret(0); | 1124 __ ret(0); |
| 1127 } | 1125 } |
| 1128 | 1126 |
| 1129 | 1127 |
| 1130 void StubCompiler::GenerateLoadInterceptor(JSObject* object, | 1128 void StubCompiler::GenerateLoadInterceptor(JSObject* object, |
| 1131 JSObject* interceptor_holder, | 1129 JSObject* interceptor_holder, |
| 1132 LookupResult* lookup, | 1130 LookupResult* lookup, |
| 1133 Register receiver, | 1131 Register receiver, |
| 1134 Register name_reg, | 1132 Register name_reg, |
| 1135 Register scratch1, | 1133 Register scratch1, |
| 1136 Register scratch2, | 1134 Register scratch2, |
| 1137 Register scratch3, | 1135 Register scratch3, |
| 1138 String* name, | 1136 String* name, |
| 1139 Label* miss) { | 1137 Label* miss) { |
| 1140 ASSERT(interceptor_holder->HasNamedInterceptor()); | 1138 ASSERT(interceptor_holder->HasNamedInterceptor()); |
| 1141 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); | 1139 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 1142 | 1140 |
| 1143 // Check that the receiver isn't a smi. | 1141 // Check that the receiver isn't a smi. |
| 1144 __ test(receiver, Immediate(kSmiTagMask)); | 1142 __ JumpIfSmi(receiver, miss); |
| 1145 __ j(zero, miss); | |
| 1146 | 1143 |
| 1147 // So far the most popular follow ups for interceptor loads are FIELD | 1144 // So far the most popular follow ups for interceptor loads are FIELD |
| 1148 // and CALLBACKS, so inline only them, other cases may be added | 1145 // and CALLBACKS, so inline only them, other cases may be added |
| 1149 // later. | 1146 // later. |
| 1150 bool compile_followup_inline = false; | 1147 bool compile_followup_inline = false; |
| 1151 if (lookup->IsProperty() && lookup->IsCacheable()) { | 1148 if (lookup->IsProperty() && lookup->IsCacheable()) { |
| 1152 if (lookup->type() == FIELD) { | 1149 if (lookup->type() == FIELD) { |
| 1153 compile_followup_inline = true; | 1150 compile_followup_inline = true; |
| 1154 } else if (lookup->type() == CALLBACKS && | 1151 } else if (lookup->type() == CALLBACKS && |
| 1155 lookup->GetCallbackObject()->IsAccessorInfo() && | 1152 lookup->GetCallbackObject()->IsAccessorInfo() && |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1285 // Get the number of arguments. | 1282 // Get the number of arguments. |
| 1286 const int argc = arguments().immediate(); | 1283 const int argc = arguments().immediate(); |
| 1287 | 1284 |
| 1288 // Get the receiver from the stack. | 1285 // Get the receiver from the stack. |
| 1289 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1286 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1290 | 1287 |
| 1291 // If the object is the holder then we know that it's a global | 1288 // If the object is the holder then we know that it's a global |
| 1292 // object which can only happen for contextual calls. In this case, | 1289 // object which can only happen for contextual calls. In this case, |
| 1293 // the receiver cannot be a smi. | 1290 // the receiver cannot be a smi. |
| 1294 if (object != holder) { | 1291 if (object != holder) { |
| 1295 __ test(edx, Immediate(kSmiTagMask)); | 1292 __ JumpIfSmi(edx, miss); |
| 1296 __ j(zero, miss); | |
| 1297 } | 1293 } |
| 1298 | 1294 |
| 1299 // Check that the maps haven't changed. | 1295 // Check that the maps haven't changed. |
| 1300 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss); | 1296 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss); |
| 1301 } | 1297 } |
| 1302 | 1298 |
| 1303 | 1299 |
| 1304 void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, | 1300 void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, |
| 1305 JSFunction* function, | 1301 JSFunction* function, |
| 1306 Label* miss) { | 1302 Label* miss) { |
| 1307 // Get the value from the cell. | 1303 // Get the value from the cell. |
| 1308 if (Serializer::enabled()) { | 1304 if (Serializer::enabled()) { |
| 1309 __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell))); | 1305 __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
| 1310 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset)); | 1306 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset)); |
| 1311 } else { | 1307 } else { |
| 1312 __ mov(edi, Operand::Cell(Handle<JSGlobalPropertyCell>(cell))); | 1308 __ mov(edi, Operand::Cell(Handle<JSGlobalPropertyCell>(cell))); |
| 1313 } | 1309 } |
| 1314 | 1310 |
| 1315 // Check that the cell contains the same function. | 1311 // Check that the cell contains the same function. |
| 1316 if (isolate()->heap()->InNewSpace(function)) { | 1312 if (isolate()->heap()->InNewSpace(function)) { |
| 1317 // We can't embed a pointer to a function in new space so we have | 1313 // We can't embed a pointer to a function in new space so we have |
| 1318 // to verify that the shared function info is unchanged. This has | 1314 // to verify that the shared function info is unchanged. This has |
| 1319 // the nice side effect that multiple closures based on the same | 1315 // the nice side effect that multiple closures based on the same |
| 1320 // function can all use this call IC. Before we load through the | 1316 // function can all use this call IC. Before we load through the |
| 1321 // function, we have to verify that it still is a function. | 1317 // function, we have to verify that it still is a function. |
| 1322 __ test(edi, Immediate(kSmiTagMask)); | 1318 __ JumpIfSmi(edi, miss); |
| 1323 __ j(zero, miss); | |
| 1324 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); | 1319 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); |
| 1325 __ j(not_equal, miss); | 1320 __ j(not_equal, miss); |
| 1326 | 1321 |
| 1327 // Check the shared function info. Make sure it hasn't changed. | 1322 // Check the shared function info. Make sure it hasn't changed. |
| 1328 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset), | 1323 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset), |
| 1329 Immediate(Handle<SharedFunctionInfo>(function->shared()))); | 1324 Immediate(Handle<SharedFunctionInfo>(function->shared()))); |
| 1330 __ j(not_equal, miss); | 1325 __ j(not_equal, miss); |
| 1331 } else { | 1326 } else { |
| 1332 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function))); | 1327 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function))); |
| 1333 __ j(not_equal, miss); | 1328 __ j(not_equal, miss); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1361 // ----------------------------------- | 1356 // ----------------------------------- |
| 1362 Label miss; | 1357 Label miss; |
| 1363 | 1358 |
| 1364 GenerateNameCheck(name, &miss); | 1359 GenerateNameCheck(name, &miss); |
| 1365 | 1360 |
| 1366 // Get the receiver from the stack. | 1361 // Get the receiver from the stack. |
| 1367 const int argc = arguments().immediate(); | 1362 const int argc = arguments().immediate(); |
| 1368 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1363 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1369 | 1364 |
| 1370 // Check that the receiver isn't a smi. | 1365 // Check that the receiver isn't a smi. |
| 1371 __ test(edx, Immediate(kSmiTagMask)); | 1366 __ JumpIfSmi(edx, &miss); |
| 1372 __ j(zero, &miss); | |
| 1373 | 1367 |
| 1374 // Do the right check and compute the holder register. | 1368 // Do the right check and compute the holder register. |
| 1375 Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi, | 1369 Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi, |
| 1376 name, &miss); | 1370 name, &miss); |
| 1377 | 1371 |
| 1378 GenerateFastPropertyLoad(masm(), edi, reg, holder, index); | 1372 GenerateFastPropertyLoad(masm(), edi, reg, holder, index); |
| 1379 | 1373 |
| 1380 // Check that the function really is a function. | 1374 // Check that the function really is a function. |
| 1381 __ test(edi, Immediate(kSmiTagMask)); | 1375 __ JumpIfSmi(edi, &miss); |
| 1382 __ j(zero, &miss); | |
| 1383 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); | 1376 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); |
| 1384 __ j(not_equal, &miss); | 1377 __ j(not_equal, &miss); |
| 1385 | 1378 |
| 1386 // Patch the receiver on the stack with the global proxy if | 1379 // Patch the receiver on the stack with the global proxy if |
| 1387 // necessary. | 1380 // necessary. |
| 1388 if (object->IsGlobalObject()) { | 1381 if (object->IsGlobalObject()) { |
| 1389 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 1382 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
| 1390 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | 1383 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); |
| 1391 } | 1384 } |
| 1392 | 1385 |
| 1393 // Invoke the function. | 1386 // Invoke the function. |
| 1394 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION); | 1387 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) |
| 1388 ? CALL_AS_FUNCTION |
| 1389 : CALL_AS_METHOD; |
| 1390 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION, |
| 1391 NullCallWrapper(), call_kind); |
| 1395 | 1392 |
| 1396 // Handle call cache miss. | 1393 // Handle call cache miss. |
| 1397 __ bind(&miss); | 1394 __ bind(&miss); |
| 1398 MaybeObject* maybe_result = GenerateMissBranch(); | 1395 MaybeObject* maybe_result = GenerateMissBranch(); |
| 1399 if (maybe_result->IsFailure()) return maybe_result; | 1396 if (maybe_result->IsFailure()) return maybe_result; |
| 1400 | 1397 |
| 1401 // Return the generated code. | 1398 // Return the generated code. |
| 1402 return GetCode(FIELD, name); | 1399 return GetCode(FIELD, name); |
| 1403 } | 1400 } |
| 1404 | 1401 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1423 | 1420 |
| 1424 Label miss; | 1421 Label miss; |
| 1425 | 1422 |
| 1426 GenerateNameCheck(name, &miss); | 1423 GenerateNameCheck(name, &miss); |
| 1427 | 1424 |
| 1428 // Get the receiver from the stack. | 1425 // Get the receiver from the stack. |
| 1429 const int argc = arguments().immediate(); | 1426 const int argc = arguments().immediate(); |
| 1430 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1427 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1431 | 1428 |
| 1432 // Check that the receiver isn't a smi. | 1429 // Check that the receiver isn't a smi. |
| 1433 __ test(edx, Immediate(kSmiTagMask)); | 1430 __ JumpIfSmi(edx, &miss); |
| 1434 __ j(zero, &miss); | |
| 1435 | 1431 |
| 1436 CheckPrototypes(JSObject::cast(object), edx, | 1432 CheckPrototypes(JSObject::cast(object), edx, |
| 1437 holder, ebx, | 1433 holder, ebx, |
| 1438 eax, edi, name, &miss); | 1434 eax, edi, name, &miss); |
| 1439 | 1435 |
| 1440 if (argc == 0) { | 1436 if (argc == 0) { |
| 1441 // Noop, return the length. | 1437 // Noop, return the length. |
| 1442 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); | 1438 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); |
| 1443 __ ret((argc + 1) * kPointerSize); | 1439 __ ret((argc + 1) * kPointerSize); |
| 1444 } else { | 1440 } else { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1472 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); | 1468 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); |
| 1473 | 1469 |
| 1474 // Push the element. | 1470 // Push the element. |
| 1475 __ lea(edx, FieldOperand(ebx, | 1471 __ lea(edx, FieldOperand(ebx, |
| 1476 eax, times_half_pointer_size, | 1472 eax, times_half_pointer_size, |
| 1477 FixedArray::kHeaderSize - argc * kPointerSize)); | 1473 FixedArray::kHeaderSize - argc * kPointerSize)); |
| 1478 __ mov(ecx, Operand(esp, argc * kPointerSize)); | 1474 __ mov(ecx, Operand(esp, argc * kPointerSize)); |
| 1479 __ mov(Operand(edx, 0), ecx); | 1475 __ mov(Operand(edx, 0), ecx); |
| 1480 | 1476 |
| 1481 // Check if value is a smi. | 1477 // Check if value is a smi. |
| 1482 __ test(ecx, Immediate(kSmiTagMask)); | 1478 __ JumpIfNotSmi(ecx, &with_write_barrier); |
| 1483 __ j(not_zero, &with_write_barrier, Label::kNear); | |
| 1484 | 1479 |
| 1485 __ bind(&exit); | 1480 __ bind(&exit); |
| 1486 __ ret((argc + 1) * kPointerSize); | 1481 __ ret((argc + 1) * kPointerSize); |
| 1487 | 1482 |
| 1488 __ bind(&with_write_barrier); | 1483 __ bind(&with_write_barrier); |
| 1489 | 1484 |
| 1490 __ RecordWrite( | 1485 __ RecordWrite( |
| 1491 ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | 1486 ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| 1492 | 1487 |
| 1493 __ ret((argc + 1) * kPointerSize); | 1488 __ ret((argc + 1) * kPointerSize); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1591 | 1586 |
| 1592 Label miss, return_undefined, call_builtin; | 1587 Label miss, return_undefined, call_builtin; |
| 1593 | 1588 |
| 1594 GenerateNameCheck(name, &miss); | 1589 GenerateNameCheck(name, &miss); |
| 1595 | 1590 |
| 1596 // Get the receiver from the stack. | 1591 // Get the receiver from the stack. |
| 1597 const int argc = arguments().immediate(); | 1592 const int argc = arguments().immediate(); |
| 1598 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1593 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1599 | 1594 |
| 1600 // Check that the receiver isn't a smi. | 1595 // Check that the receiver isn't a smi. |
| 1601 __ test(edx, Immediate(kSmiTagMask)); | 1596 __ JumpIfSmi(edx, &miss); |
| 1602 __ j(zero, &miss); | |
| 1603 CheckPrototypes(JSObject::cast(object), edx, | 1597 CheckPrototypes(JSObject::cast(object), edx, |
| 1604 holder, ebx, | 1598 holder, ebx, |
| 1605 eax, edi, name, &miss); | 1599 eax, edi, name, &miss); |
| 1606 | 1600 |
| 1607 // Get the elements array of the object. | 1601 // Get the elements array of the object. |
| 1608 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); | 1602 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); |
| 1609 | 1603 |
| 1610 // Check that the elements are in fast mode and writable. | 1604 // Check that the elements are in fast mode and writable. |
| 1611 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 1605 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
| 1612 Immediate(factory()->fixed_array_map())); | 1606 Immediate(factory()->fixed_array_map())); |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1851 return isolate()->heap()->undefined_value(); | 1845 return isolate()->heap()->undefined_value(); |
| 1852 } | 1846 } |
| 1853 | 1847 |
| 1854 Label miss; | 1848 Label miss; |
| 1855 GenerateNameCheck(name, &miss); | 1849 GenerateNameCheck(name, &miss); |
| 1856 | 1850 |
| 1857 if (cell == NULL) { | 1851 if (cell == NULL) { |
| 1858 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 1852 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 1859 | 1853 |
| 1860 STATIC_ASSERT(kSmiTag == 0); | 1854 STATIC_ASSERT(kSmiTag == 0); |
| 1861 __ test(edx, Immediate(kSmiTagMask)); | 1855 __ JumpIfSmi(edx, &miss); |
| 1862 __ j(zero, &miss); | |
| 1863 | 1856 |
| 1864 CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name, | 1857 CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name, |
| 1865 &miss); | 1858 &miss); |
| 1866 } else { | 1859 } else { |
| 1867 ASSERT(cell->value() == function); | 1860 ASSERT(cell->value() == function); |
| 1868 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); | 1861 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); |
| 1869 GenerateLoadFunctionFromCell(cell, function, &miss); | 1862 GenerateLoadFunctionFromCell(cell, function, &miss); |
| 1870 } | 1863 } |
| 1871 | 1864 |
| 1872 // Load the char code argument. | 1865 // Load the char code argument. |
| 1873 Register code = ebx; | 1866 Register code = ebx; |
| 1874 __ mov(code, Operand(esp, 1 * kPointerSize)); | 1867 __ mov(code, Operand(esp, 1 * kPointerSize)); |
| 1875 | 1868 |
| 1876 // Check the code is a smi. | 1869 // Check the code is a smi. |
| 1877 Label slow; | 1870 Label slow; |
| 1878 STATIC_ASSERT(kSmiTag == 0); | 1871 STATIC_ASSERT(kSmiTag == 0); |
| 1879 __ test(code, Immediate(kSmiTagMask)); | 1872 __ JumpIfNotSmi(code, &slow); |
| 1880 __ j(not_zero, &slow); | |
| 1881 | 1873 |
| 1882 // Convert the smi code to uint16. | 1874 // Convert the smi code to uint16. |
| 1883 __ and_(code, Immediate(Smi::FromInt(0xffff))); | 1875 __ and_(code, Immediate(Smi::FromInt(0xffff))); |
| 1884 | 1876 |
| 1885 StringCharFromCodeGenerator char_from_code_generator(code, eax); | 1877 StringCharFromCodeGenerator char_from_code_generator(code, eax); |
| 1886 char_from_code_generator.GenerateFast(masm()); | 1878 char_from_code_generator.GenerateFast(masm()); |
| 1887 __ ret(2 * kPointerSize); | 1879 __ ret(2 * kPointerSize); |
| 1888 | 1880 |
| 1889 StubRuntimeCallHelper call_helper; | 1881 StubRuntimeCallHelper call_helper; |
| 1890 char_from_code_generator.GenerateSlow(masm(), call_helper); | 1882 char_from_code_generator.GenerateSlow(masm(), call_helper); |
| 1891 | 1883 |
| 1892 // Tail call the full function. We do not have to patch the receiver | 1884 // Tail call the full function. We do not have to patch the receiver |
| 1893 // because the function makes no use of it. | 1885 // because the function makes no use of it. |
| 1894 __ bind(&slow); | 1886 __ bind(&slow); |
| 1895 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); | 1887 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) |
| 1888 ? CALL_AS_FUNCTION |
| 1889 : CALL_AS_METHOD; |
| 1890 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, |
| 1891 NullCallWrapper(), call_kind); |
| 1896 | 1892 |
| 1897 __ bind(&miss); | 1893 __ bind(&miss); |
| 1898 // ecx: function name. | 1894 // ecx: function name. |
| 1899 MaybeObject* maybe_result = GenerateMissBranch(); | 1895 MaybeObject* maybe_result = GenerateMissBranch(); |
| 1900 if (maybe_result->IsFailure()) return maybe_result; | 1896 if (maybe_result->IsFailure()) return maybe_result; |
| 1901 | 1897 |
| 1902 // Return the generated code. | 1898 // Return the generated code. |
| 1903 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); | 1899 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); |
| 1904 } | 1900 } |
| 1905 | 1901 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1931 return isolate()->heap()->undefined_value(); | 1927 return isolate()->heap()->undefined_value(); |
| 1932 } | 1928 } |
| 1933 | 1929 |
| 1934 Label miss; | 1930 Label miss; |
| 1935 GenerateNameCheck(name, &miss); | 1931 GenerateNameCheck(name, &miss); |
| 1936 | 1932 |
| 1937 if (cell == NULL) { | 1933 if (cell == NULL) { |
| 1938 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 1934 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 1939 | 1935 |
| 1940 STATIC_ASSERT(kSmiTag == 0); | 1936 STATIC_ASSERT(kSmiTag == 0); |
| 1941 __ test(edx, Immediate(kSmiTagMask)); | 1937 __ JumpIfSmi(edx, &miss); |
| 1942 __ j(zero, &miss); | |
| 1943 | 1938 |
| 1944 CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name, | 1939 CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name, |
| 1945 &miss); | 1940 &miss); |
| 1946 } else { | 1941 } else { |
| 1947 ASSERT(cell->value() == function); | 1942 ASSERT(cell->value() == function); |
| 1948 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); | 1943 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); |
| 1949 GenerateLoadFunctionFromCell(cell, function, &miss); | 1944 GenerateLoadFunctionFromCell(cell, function, &miss); |
| 1950 } | 1945 } |
| 1951 | 1946 |
| 1952 // Load the (only) argument into eax. | 1947 // Load the (only) argument into eax. |
| 1953 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 1948 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 1954 | 1949 |
| 1955 // Check if the argument is a smi. | 1950 // Check if the argument is a smi. |
| 1956 Label smi; | 1951 Label smi; |
| 1957 STATIC_ASSERT(kSmiTag == 0); | 1952 STATIC_ASSERT(kSmiTag == 0); |
| 1958 __ test(eax, Immediate(kSmiTagMask)); | 1953 __ JumpIfSmi(eax, &smi); |
| 1959 __ j(zero, &smi); | |
| 1960 | 1954 |
| 1961 // Check if the argument is a heap number and load its value into xmm0. | 1955 // Check if the argument is a heap number and load its value into xmm0. |
| 1962 Label slow; | 1956 Label slow; |
| 1963 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK); | 1957 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK); |
| 1964 __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); | 1958 __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 1965 | 1959 |
| 1966 // Check if the argument is strictly positive. Note this also | 1960 // Check if the argument is strictly positive. Note this also |
| 1967 // discards NaN. | 1961 // discards NaN. |
| 1968 __ xorpd(xmm1, xmm1); | 1962 __ xorpd(xmm1, xmm1); |
| 1969 __ ucomisd(xmm0, xmm1); | 1963 __ ucomisd(xmm0, xmm1); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2015 __ ret(2 * kPointerSize); | 2009 __ ret(2 * kPointerSize); |
| 2016 | 2010 |
| 2017 // Return the argument (when it's an already round heap number). | 2011 // Return the argument (when it's an already round heap number). |
| 2018 __ bind(&already_round); | 2012 __ bind(&already_round); |
| 2019 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 2013 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 2020 __ ret(2 * kPointerSize); | 2014 __ ret(2 * kPointerSize); |
| 2021 | 2015 |
| 2022 // Tail call the full function. We do not have to patch the receiver | 2016 // Tail call the full function. We do not have to patch the receiver |
| 2023 // because the function makes no use of it. | 2017 // because the function makes no use of it. |
| 2024 __ bind(&slow); | 2018 __ bind(&slow); |
| 2025 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); | 2019 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, |
| 2020 NullCallWrapper(), CALL_AS_METHOD); |
| 2026 | 2021 |
| 2027 __ bind(&miss); | 2022 __ bind(&miss); |
| 2028 // ecx: function name. | 2023 // ecx: function name. |
| 2029 MaybeObject* maybe_result = GenerateMissBranch(); | 2024 MaybeObject* maybe_result = GenerateMissBranch(); |
| 2030 if (maybe_result->IsFailure()) return maybe_result; | 2025 if (maybe_result->IsFailure()) return maybe_result; |
| 2031 | 2026 |
| 2032 // Return the generated code. | 2027 // Return the generated code. |
| 2033 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); | 2028 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); |
| 2034 } | 2029 } |
| 2035 | 2030 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2055 return isolate()->heap()->undefined_value(); | 2050 return isolate()->heap()->undefined_value(); |
| 2056 } | 2051 } |
| 2057 | 2052 |
| 2058 Label miss; | 2053 Label miss; |
| 2059 GenerateNameCheck(name, &miss); | 2054 GenerateNameCheck(name, &miss); |
| 2060 | 2055 |
| 2061 if (cell == NULL) { | 2056 if (cell == NULL) { |
| 2062 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 2057 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 2063 | 2058 |
| 2064 STATIC_ASSERT(kSmiTag == 0); | 2059 STATIC_ASSERT(kSmiTag == 0); |
| 2065 __ test(edx, Immediate(kSmiTagMask)); | 2060 __ JumpIfSmi(edx, &miss); |
| 2066 __ j(zero, &miss); | |
| 2067 | 2061 |
| 2068 CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name, | 2062 CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name, |
| 2069 &miss); | 2063 &miss); |
| 2070 } else { | 2064 } else { |
| 2071 ASSERT(cell->value() == function); | 2065 ASSERT(cell->value() == function); |
| 2072 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); | 2066 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); |
| 2073 GenerateLoadFunctionFromCell(cell, function, &miss); | 2067 GenerateLoadFunctionFromCell(cell, function, &miss); |
| 2074 } | 2068 } |
| 2075 | 2069 |
| 2076 // Load the (only) argument into eax. | 2070 // Load the (only) argument into eax. |
| 2077 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 2071 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 2078 | 2072 |
| 2079 // Check if the argument is a smi. | 2073 // Check if the argument is a smi. |
| 2080 Label not_smi; | 2074 Label not_smi; |
| 2081 STATIC_ASSERT(kSmiTag == 0); | 2075 STATIC_ASSERT(kSmiTag == 0); |
| 2082 __ test(eax, Immediate(kSmiTagMask)); | 2076 __ JumpIfNotSmi(eax, ¬_smi); |
| 2083 __ j(not_zero, ¬_smi); | |
| 2084 | 2077 |
| 2085 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0 | 2078 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0 |
| 2086 // otherwise. | 2079 // otherwise. |
| 2087 __ mov(ebx, eax); | 2080 __ mov(ebx, eax); |
| 2088 __ sar(ebx, kBitsPerInt - 1); | 2081 __ sar(ebx, kBitsPerInt - 1); |
| 2089 | 2082 |
| 2090 // Do bitwise not or do nothing depending on ebx. | 2083 // Do bitwise not or do nothing depending on ebx. |
| 2091 __ xor_(eax, Operand(ebx)); | 2084 __ xor_(eax, Operand(ebx)); |
| 2092 | 2085 |
| 2093 // Add 1 or do nothing depending on ebx. | 2086 // Add 1 or do nothing depending on ebx. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2120 __ and_(ebx, ~HeapNumber::kSignMask); | 2113 __ and_(ebx, ~HeapNumber::kSignMask); |
| 2121 __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset)); | 2114 __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset)); |
| 2122 __ AllocateHeapNumber(eax, edi, edx, &slow); | 2115 __ AllocateHeapNumber(eax, edi, edx, &slow); |
| 2123 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx); | 2116 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx); |
| 2124 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); | 2117 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); |
| 2125 __ ret(2 * kPointerSize); | 2118 __ ret(2 * kPointerSize); |
| 2126 | 2119 |
| 2127 // Tail call the full function. We do not have to patch the receiver | 2120 // Tail call the full function. We do not have to patch the receiver |
| 2128 // because the function makes no use of it. | 2121 // because the function makes no use of it. |
| 2129 __ bind(&slow); | 2122 __ bind(&slow); |
| 2130 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); | 2123 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, |
| 2124 NullCallWrapper(), CALL_AS_METHOD); |
| 2131 | 2125 |
| 2132 __ bind(&miss); | 2126 __ bind(&miss); |
| 2133 // ecx: function name. | 2127 // ecx: function name. |
| 2134 MaybeObject* maybe_result = GenerateMissBranch(); | 2128 MaybeObject* maybe_result = GenerateMissBranch(); |
| 2135 if (maybe_result->IsFailure()) return maybe_result; | 2129 if (maybe_result->IsFailure()) return maybe_result; |
| 2136 | 2130 |
| 2137 // Return the generated code. | 2131 // Return the generated code. |
| 2138 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); | 2132 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); |
| 2139 } | 2133 } |
| 2140 | 2134 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2158 | 2152 |
| 2159 Label miss, miss_before_stack_reserved; | 2153 Label miss, miss_before_stack_reserved; |
| 2160 | 2154 |
| 2161 GenerateNameCheck(name, &miss_before_stack_reserved); | 2155 GenerateNameCheck(name, &miss_before_stack_reserved); |
| 2162 | 2156 |
| 2163 // Get the receiver from the stack. | 2157 // Get the receiver from the stack. |
| 2164 const int argc = arguments().immediate(); | 2158 const int argc = arguments().immediate(); |
| 2165 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2159 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2166 | 2160 |
| 2167 // Check that the receiver isn't a smi. | 2161 // Check that the receiver isn't a smi. |
| 2168 __ test(edx, Immediate(kSmiTagMask)); | 2162 __ JumpIfSmi(edx, &miss_before_stack_reserved); |
| 2169 __ j(zero, &miss_before_stack_reserved); | |
| 2170 | 2163 |
| 2171 Counters* counters = isolate()->counters(); | 2164 Counters* counters = isolate()->counters(); |
| 2172 __ IncrementCounter(counters->call_const(), 1); | 2165 __ IncrementCounter(counters->call_const(), 1); |
| 2173 __ IncrementCounter(counters->call_const_fast_api(), 1); | 2166 __ IncrementCounter(counters->call_const_fast_api(), 1); |
| 2174 | 2167 |
| 2175 // Allocate space for v8::Arguments implicit values. Must be initialized | 2168 // Allocate space for v8::Arguments implicit values. Must be initialized |
| 2176 // before calling any runtime function. | 2169 // before calling any runtime function. |
| 2177 __ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize)); | 2170 __ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize)); |
| 2178 | 2171 |
| 2179 // Check that the maps haven't changed and find a Holder as a side effect. | 2172 // Check that the maps haven't changed and find a Holder as a side effect. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2194 | 2187 |
| 2195 __ bind(&miss_before_stack_reserved); | 2188 __ bind(&miss_before_stack_reserved); |
| 2196 MaybeObject* maybe_result = GenerateMissBranch(); | 2189 MaybeObject* maybe_result = GenerateMissBranch(); |
| 2197 if (maybe_result->IsFailure()) return maybe_result; | 2190 if (maybe_result->IsFailure()) return maybe_result; |
| 2198 | 2191 |
| 2199 // Return the generated code. | 2192 // Return the generated code. |
| 2200 return GetCode(function); | 2193 return GetCode(function); |
| 2201 } | 2194 } |
| 2202 | 2195 |
| 2203 | 2196 |
| 2204 MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, | 2197 MaybeObject* CallStubCompiler::CompileCallConstant( |
| 2205 JSObject* holder, | 2198 Object* object, |
| 2206 JSFunction* function, | 2199 JSObject* holder, |
| 2207 String* name, | 2200 JSFunction* function, |
| 2208 CheckType check) { | 2201 String* name, |
| 2202 CheckType check) { |
| 2209 // ----------- S t a t e ------------- | 2203 // ----------- S t a t e ------------- |
| 2210 // -- ecx : name | 2204 // -- ecx : name |
| 2211 // -- esp[0] : return address | 2205 // -- esp[0] : return address |
| 2212 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 2206 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 2213 // -- ... | 2207 // -- ... |
| 2214 // -- esp[(argc + 1) * 4] : receiver | 2208 // -- esp[(argc + 1) * 4] : receiver |
| 2215 // ----------------------------------- | 2209 // ----------------------------------- |
| 2216 | 2210 |
| 2217 if (HasCustomCallGenerator(function)) { | 2211 if (HasCustomCallGenerator(function)) { |
| 2218 MaybeObject* maybe_result = CompileCustomCall( | 2212 MaybeObject* maybe_result = CompileCustomCall( |
| 2219 object, holder, NULL, function, name); | 2213 object, holder, NULL, function, name); |
| 2220 Object* result; | 2214 Object* result; |
| 2221 if (!maybe_result->ToObject(&result)) return maybe_result; | 2215 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 2222 // undefined means bail out to regular compiler. | 2216 // undefined means bail out to regular compiler. |
| 2223 if (!result->IsUndefined()) return result; | 2217 if (!result->IsUndefined()) return result; |
| 2224 } | 2218 } |
| 2225 | 2219 |
| 2226 Label miss; | 2220 Label miss; |
| 2227 | 2221 |
| 2228 GenerateNameCheck(name, &miss); | 2222 GenerateNameCheck(name, &miss); |
| 2229 | 2223 |
| 2230 // Get the receiver from the stack. | 2224 // Get the receiver from the stack. |
| 2231 const int argc = arguments().immediate(); | 2225 const int argc = arguments().immediate(); |
| 2232 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2226 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2233 | 2227 |
| 2234 // Check that the receiver isn't a smi. | 2228 // Check that the receiver isn't a smi. |
| 2235 if (check != NUMBER_CHECK) { | 2229 if (check != NUMBER_CHECK) { |
| 2236 __ test(edx, Immediate(kSmiTagMask)); | 2230 __ JumpIfSmi(edx, &miss); |
| 2237 __ j(zero, &miss); | |
| 2238 } | 2231 } |
| 2239 | 2232 |
| 2240 // Make sure that it's okay not to patch the on stack receiver | 2233 // Make sure that it's okay not to patch the on stack receiver |
| 2241 // unless we're doing a receiver map check. | 2234 // unless we're doing a receiver map check. |
| 2242 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); | 2235 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); |
| 2243 | 2236 |
| 2244 SharedFunctionInfo* function_info = function->shared(); | 2237 SharedFunctionInfo* function_info = function->shared(); |
| 2245 switch (check) { | 2238 switch (check) { |
| 2246 case RECEIVER_MAP_CHECK: | 2239 case RECEIVER_MAP_CHECK: |
| 2247 __ IncrementCounter(isolate()->counters()->call_const(), 1); | 2240 __ IncrementCounter(isolate()->counters()->call_const(), 1); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2276 break; | 2269 break; |
| 2277 | 2270 |
| 2278 case NUMBER_CHECK: { | 2271 case NUMBER_CHECK: { |
| 2279 if (!function->IsBuiltin() && !function_info->strict_mode()) { | 2272 if (!function->IsBuiltin() && !function_info->strict_mode()) { |
| 2280 // Calling non-strict non-builtins with a value as the receiver | 2273 // Calling non-strict non-builtins with a value as the receiver |
| 2281 // requires boxing. | 2274 // requires boxing. |
| 2282 __ jmp(&miss); | 2275 __ jmp(&miss); |
| 2283 } else { | 2276 } else { |
| 2284 Label fast; | 2277 Label fast; |
| 2285 // Check that the object is a smi or a heap number. | 2278 // Check that the object is a smi or a heap number. |
| 2286 __ test(edx, Immediate(kSmiTagMask)); | 2279 __ JumpIfSmi(edx, &fast); |
| 2287 __ j(zero, &fast); | |
| 2288 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax); | 2280 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax); |
| 2289 __ j(not_equal, &miss); | 2281 __ j(not_equal, &miss); |
| 2290 __ bind(&fast); | 2282 __ bind(&fast); |
| 2291 // Check that the maps starting from the prototype haven't changed. | 2283 // Check that the maps starting from the prototype haven't changed. |
| 2292 GenerateDirectLoadGlobalFunctionPrototype( | 2284 GenerateDirectLoadGlobalFunctionPrototype( |
| 2293 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss); | 2285 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss); |
| 2294 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 2286 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
| 2295 ebx, edx, edi, name, &miss); | 2287 ebx, edx, edi, name, &miss); |
| 2296 } | 2288 } |
| 2297 break; | 2289 break; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2316 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 2308 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
| 2317 ebx, edx, edi, name, &miss); | 2309 ebx, edx, edi, name, &miss); |
| 2318 } | 2310 } |
| 2319 break; | 2311 break; |
| 2320 } | 2312 } |
| 2321 | 2313 |
| 2322 default: | 2314 default: |
| 2323 UNREACHABLE(); | 2315 UNREACHABLE(); |
| 2324 } | 2316 } |
| 2325 | 2317 |
| 2326 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); | 2318 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) |
| 2319 ? CALL_AS_FUNCTION |
| 2320 : CALL_AS_METHOD; |
| 2321 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, |
| 2322 NullCallWrapper(), call_kind); |
| 2327 | 2323 |
| 2328 // Handle call cache miss. | 2324 // Handle call cache miss. |
| 2329 __ bind(&miss); | 2325 __ bind(&miss); |
| 2330 MaybeObject* maybe_result = GenerateMissBranch(); | 2326 MaybeObject* maybe_result = GenerateMissBranch(); |
| 2331 if (maybe_result->IsFailure()) return maybe_result; | 2327 if (maybe_result->IsFailure()) return maybe_result; |
| 2332 | 2328 |
| 2333 // Return the generated code. | 2329 // Return the generated code. |
| 2334 return GetCode(function); | 2330 return GetCode(function); |
| 2335 } | 2331 } |
| 2336 | 2332 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2351 | 2347 |
| 2352 // Get the number of arguments. | 2348 // Get the number of arguments. |
| 2353 const int argc = arguments().immediate(); | 2349 const int argc = arguments().immediate(); |
| 2354 | 2350 |
| 2355 LookupResult lookup; | 2351 LookupResult lookup; |
| 2356 LookupPostInterceptor(holder, name, &lookup); | 2352 LookupPostInterceptor(holder, name, &lookup); |
| 2357 | 2353 |
| 2358 // Get the receiver from the stack. | 2354 // Get the receiver from the stack. |
| 2359 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2355 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2360 | 2356 |
| 2361 CallInterceptorCompiler compiler(this, arguments(), ecx); | 2357 CallInterceptorCompiler compiler(this, arguments(), ecx, extra_ic_state_); |
| 2362 MaybeObject* result = compiler.Compile(masm(), | 2358 MaybeObject* result = compiler.Compile(masm(), |
| 2363 object, | 2359 object, |
| 2364 holder, | 2360 holder, |
| 2365 name, | 2361 name, |
| 2366 &lookup, | 2362 &lookup, |
| 2367 edx, | 2363 edx, |
| 2368 ebx, | 2364 ebx, |
| 2369 edi, | 2365 edi, |
| 2370 eax, | 2366 eax, |
| 2371 &miss); | 2367 &miss); |
| 2372 if (result->IsFailure()) return result; | 2368 if (result->IsFailure()) return result; |
| 2373 | 2369 |
| 2374 // Restore receiver. | 2370 // Restore receiver. |
| 2375 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2371 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2376 | 2372 |
| 2377 // Check that the function really is a function. | 2373 // Check that the function really is a function. |
| 2378 __ test(eax, Immediate(kSmiTagMask)); | 2374 __ JumpIfSmi(eax, &miss); |
| 2379 __ j(zero, &miss); | |
| 2380 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); | 2375 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); |
| 2381 __ j(not_equal, &miss); | 2376 __ j(not_equal, &miss); |
| 2382 | 2377 |
| 2383 // Patch the receiver on the stack with the global proxy if | 2378 // Patch the receiver on the stack with the global proxy if |
| 2384 // necessary. | 2379 // necessary. |
| 2385 if (object->IsGlobalObject()) { | 2380 if (object->IsGlobalObject()) { |
| 2386 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 2381 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
| 2387 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | 2382 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); |
| 2388 } | 2383 } |
| 2389 | 2384 |
| 2390 // Invoke the function. | 2385 // Invoke the function. |
| 2391 __ mov(edi, eax); | 2386 __ mov(edi, eax); |
| 2392 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION); | 2387 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) |
| 2388 ? CALL_AS_FUNCTION |
| 2389 : CALL_AS_METHOD; |
| 2390 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION, |
| 2391 NullCallWrapper(), call_kind); |
| 2393 | 2392 |
| 2394 // Handle load cache miss. | 2393 // Handle load cache miss. |
| 2395 __ bind(&miss); | 2394 __ bind(&miss); |
| 2396 MaybeObject* maybe_result = GenerateMissBranch(); | 2395 MaybeObject* maybe_result = GenerateMissBranch(); |
| 2397 if (maybe_result->IsFailure()) return maybe_result; | 2396 if (maybe_result->IsFailure()) return maybe_result; |
| 2398 | 2397 |
| 2399 // Return the generated code. | 2398 // Return the generated code. |
| 2400 return GetCode(INTERCEPTOR, name); | 2399 return GetCode(INTERCEPTOR, name); |
| 2401 } | 2400 } |
| 2402 | 2401 |
| 2403 | 2402 |
| 2404 MaybeObject* CallStubCompiler::CompileCallGlobal( | 2403 MaybeObject* CallStubCompiler::CompileCallGlobal( |
| 2405 JSObject* object, | 2404 JSObject* object, |
| 2406 GlobalObject* holder, | 2405 GlobalObject* holder, |
| 2407 JSGlobalPropertyCell* cell, | 2406 JSGlobalPropertyCell* cell, |
| 2408 JSFunction* function, | 2407 JSFunction* function, |
| 2409 String* name, | 2408 String* name) { |
| 2410 Code::ExtraICState extra_ic_state) { | |
| 2411 // ----------- S t a t e ------------- | 2409 // ----------- S t a t e ------------- |
| 2412 // -- ecx : name | 2410 // -- ecx : name |
| 2413 // -- esp[0] : return address | 2411 // -- esp[0] : return address |
| 2414 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 2412 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 2415 // -- ... | 2413 // -- ... |
| 2416 // -- esp[(argc + 1) * 4] : receiver | 2414 // -- esp[(argc + 1) * 4] : receiver |
| 2417 // ----------------------------------- | 2415 // ----------------------------------- |
| 2418 | 2416 |
| 2419 if (HasCustomCallGenerator(function)) { | 2417 if (HasCustomCallGenerator(function)) { |
| 2420 MaybeObject* maybe_result = CompileCustomCall( | 2418 MaybeObject* maybe_result = CompileCustomCall( |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2443 } | 2441 } |
| 2444 | 2442 |
| 2445 // Setup the context (function already in edi). | 2443 // Setup the context (function already in edi). |
| 2446 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 2444 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
| 2447 | 2445 |
| 2448 // Jump to the cached code (tail call). | 2446 // Jump to the cached code (tail call). |
| 2449 Counters* counters = isolate()->counters(); | 2447 Counters* counters = isolate()->counters(); |
| 2450 __ IncrementCounter(counters->call_global_inline(), 1); | 2448 __ IncrementCounter(counters->call_global_inline(), 1); |
| 2451 ASSERT(function->is_compiled()); | 2449 ASSERT(function->is_compiled()); |
| 2452 ParameterCount expected(function->shared()->formal_parameter_count()); | 2450 ParameterCount expected(function->shared()->formal_parameter_count()); |
| 2453 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state) | 2451 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) |
| 2454 ? CALL_AS_FUNCTION | 2452 ? CALL_AS_FUNCTION |
| 2455 : CALL_AS_METHOD; | 2453 : CALL_AS_METHOD; |
| 2456 if (V8::UseCrankshaft()) { | 2454 if (V8::UseCrankshaft()) { |
| 2457 // TODO(kasperl): For now, we always call indirectly through the | 2455 // TODO(kasperl): For now, we always call indirectly through the |
| 2458 // code field in the function to allow recompilation to take effect | 2456 // code field in the function to allow recompilation to take effect |
| 2459 // without changing any of the call sites. | 2457 // without changing any of the call sites. |
| 2460 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), | 2458 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), |
| 2461 expected, arguments(), JUMP_FUNCTION, | 2459 expected, arguments(), JUMP_FUNCTION, |
| 2462 NullCallWrapper(), call_kind); | 2460 NullCallWrapper(), call_kind); |
| 2463 } else { | 2461 } else { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2514 String* name) { | 2512 String* name) { |
| 2515 // ----------- S t a t e ------------- | 2513 // ----------- S t a t e ------------- |
| 2516 // -- eax : value | 2514 // -- eax : value |
| 2517 // -- ecx : name | 2515 // -- ecx : name |
| 2518 // -- edx : receiver | 2516 // -- edx : receiver |
| 2519 // -- esp[0] : return address | 2517 // -- esp[0] : return address |
| 2520 // ----------------------------------- | 2518 // ----------------------------------- |
| 2521 Label miss; | 2519 Label miss; |
| 2522 | 2520 |
| 2523 // Check that the object isn't a smi. | 2521 // Check that the object isn't a smi. |
| 2524 __ test(edx, Immediate(kSmiTagMask)); | 2522 __ JumpIfSmi(edx, &miss); |
| 2525 __ j(zero, &miss); | |
| 2526 | 2523 |
| 2527 // Check that the map of the object hasn't changed. | 2524 // Check that the map of the object hasn't changed. |
| 2528 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 2525 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 2529 Immediate(Handle<Map>(object->map()))); | 2526 Immediate(Handle<Map>(object->map()))); |
| 2530 __ j(not_equal, &miss); | 2527 __ j(not_equal, &miss); |
| 2531 | 2528 |
| 2532 // Perform global security token check if needed. | 2529 // Perform global security token check if needed. |
| 2533 if (object->IsJSGlobalProxy()) { | 2530 if (object->IsJSGlobalProxy()) { |
| 2534 __ CheckAccessGlobalProxy(edx, ebx, &miss); | 2531 __ CheckAccessGlobalProxy(edx, ebx, &miss); |
| 2535 } | 2532 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2564 String* name) { | 2561 String* name) { |
| 2565 // ----------- S t a t e ------------- | 2562 // ----------- S t a t e ------------- |
| 2566 // -- eax : value | 2563 // -- eax : value |
| 2567 // -- ecx : name | 2564 // -- ecx : name |
| 2568 // -- edx : receiver | 2565 // -- edx : receiver |
| 2569 // -- esp[0] : return address | 2566 // -- esp[0] : return address |
| 2570 // ----------------------------------- | 2567 // ----------------------------------- |
| 2571 Label miss; | 2568 Label miss; |
| 2572 | 2569 |
| 2573 // Check that the object isn't a smi. | 2570 // Check that the object isn't a smi. |
| 2574 __ test(edx, Immediate(kSmiTagMask)); | 2571 __ JumpIfSmi(edx, &miss); |
| 2575 __ j(zero, &miss); | |
| 2576 | 2572 |
| 2577 // Check that the map of the object hasn't changed. | 2573 // Check that the map of the object hasn't changed. |
| 2578 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 2574 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 2579 Immediate(Handle<Map>(receiver->map()))); | 2575 Immediate(Handle<Map>(receiver->map()))); |
| 2580 __ j(not_equal, &miss); | 2576 __ j(not_equal, &miss); |
| 2581 | 2577 |
| 2582 // Perform global security token check if needed. | 2578 // Perform global security token check if needed. |
| 2583 if (receiver->IsJSGlobalProxy()) { | 2579 if (receiver->IsJSGlobalProxy()) { |
| 2584 __ CheckAccessGlobalProxy(edx, ebx, &miss); | 2580 __ CheckAccessGlobalProxy(edx, ebx, &miss); |
| 2585 } | 2581 } |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2702 __ bind(&miss); | 2698 __ bind(&miss); |
| 2703 __ DecrementCounter(counters->keyed_store_field(), 1); | 2699 __ DecrementCounter(counters->keyed_store_field(), 1); |
| 2704 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); | 2700 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); |
| 2705 __ jmp(ic, RelocInfo::CODE_TARGET); | 2701 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2706 | 2702 |
| 2707 // Return the generated code. | 2703 // Return the generated code. |
| 2708 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); | 2704 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); |
| 2709 } | 2705 } |
| 2710 | 2706 |
| 2711 | 2707 |
| 2712 MaybeObject* KeyedStoreStubCompiler::CompileStoreFastElement( | 2708 MaybeObject* KeyedStoreStubCompiler::CompileStoreElement(Map* receiver_map) { |
| 2713 Map* receiver_map) { | |
| 2714 // ----------- S t a t e ------------- | 2709 // ----------- S t a t e ------------- |
| 2715 // -- eax : value | 2710 // -- eax : value |
| 2716 // -- ecx : key | 2711 // -- ecx : key |
| 2717 // -- edx : receiver | 2712 // -- edx : receiver |
| 2718 // -- esp[0] : return address | 2713 // -- esp[0] : return address |
| 2719 // ----------------------------------- | 2714 // ----------------------------------- |
| 2720 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; | 2715 Code* stub; |
| 2716 JSObject::ElementsKind elements_kind = receiver_map->elements_kind(); |
| 2717 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; |
| 2721 MaybeObject* maybe_stub = | 2718 MaybeObject* maybe_stub = |
| 2722 KeyedStoreFastElementStub(is_js_array).TryGetCode(); | 2719 KeyedStoreElementStub(is_jsarray, elements_kind).TryGetCode(); |
| 2723 Code* stub; | |
| 2724 if (!maybe_stub->To(&stub)) return maybe_stub; | 2720 if (!maybe_stub->To(&stub)) return maybe_stub; |
| 2725 __ DispatchMap(edx, | 2721 __ DispatchMap(edx, |
| 2726 Handle<Map>(receiver_map), | 2722 Handle<Map>(receiver_map), |
| 2727 Handle<Code>(stub), | 2723 Handle<Code>(stub), |
| 2728 DO_SMI_CHECK); | 2724 DO_SMI_CHECK); |
| 2729 | 2725 |
| 2730 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); | 2726 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); |
| 2731 __ jmp(ic, RelocInfo::CODE_TARGET); | 2727 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2732 | 2728 |
| 2733 // Return the generated code. | 2729 // Return the generated code. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2768 JSObject* object, | 2764 JSObject* object, |
| 2769 JSObject* last) { | 2765 JSObject* last) { |
| 2770 // ----------- S t a t e ------------- | 2766 // ----------- S t a t e ------------- |
| 2771 // -- eax : receiver | 2767 // -- eax : receiver |
| 2772 // -- ecx : name | 2768 // -- ecx : name |
| 2773 // -- esp[0] : return address | 2769 // -- esp[0] : return address |
| 2774 // ----------------------------------- | 2770 // ----------------------------------- |
| 2775 Label miss; | 2771 Label miss; |
| 2776 | 2772 |
| 2777 // Check that the receiver isn't a smi. | 2773 // Check that the receiver isn't a smi. |
| 2778 __ test(eax, Immediate(kSmiTagMask)); | 2774 __ JumpIfSmi(eax, &miss); |
| 2779 __ j(zero, &miss); | |
| 2780 | 2775 |
| 2781 ASSERT(last->IsGlobalObject() || last->HasFastProperties()); | 2776 ASSERT(last->IsGlobalObject() || last->HasFastProperties()); |
| 2782 | 2777 |
| 2783 // Check the maps of the full prototype chain. Also check that | 2778 // Check the maps of the full prototype chain. Also check that |
| 2784 // global property cells up to (but not including) the last object | 2779 // global property cells up to (but not including) the last object |
| 2785 // in the prototype chain are empty. | 2780 // in the prototype chain are empty. |
| 2786 CheckPrototypes(object, eax, last, ebx, edx, edi, name, &miss); | 2781 CheckPrototypes(object, eax, last, ebx, edx, edi, name, &miss); |
| 2787 | 2782 |
| 2788 // If the last object in the prototype chain is a global object, | 2783 // If the last object in the prototype chain is a global object, |
| 2789 // check that the global property cell is empty. | 2784 // check that the global property cell is empty. |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2921 // -- eax : receiver | 2916 // -- eax : receiver |
| 2922 // -- ecx : name | 2917 // -- ecx : name |
| 2923 // -- esp[0] : return address | 2918 // -- esp[0] : return address |
| 2924 // ----------------------------------- | 2919 // ----------------------------------- |
| 2925 Label miss; | 2920 Label miss; |
| 2926 | 2921 |
| 2927 // If the object is the holder then we know that it's a global | 2922 // If the object is the holder then we know that it's a global |
| 2928 // object which can only happen for contextual loads. In this case, | 2923 // object which can only happen for contextual loads. In this case, |
| 2929 // the receiver cannot be a smi. | 2924 // the receiver cannot be a smi. |
| 2930 if (object != holder) { | 2925 if (object != holder) { |
| 2931 __ test(eax, Immediate(kSmiTagMask)); | 2926 __ JumpIfSmi(eax, &miss); |
| 2932 __ j(zero, &miss); | |
| 2933 } | 2927 } |
| 2934 | 2928 |
| 2935 // Check that the maps haven't changed. | 2929 // Check that the maps haven't changed. |
| 2936 CheckPrototypes(object, eax, holder, ebx, edx, edi, name, &miss); | 2930 CheckPrototypes(object, eax, holder, ebx, edx, edi, name, &miss); |
| 2937 | 2931 |
| 2938 // Get the value from the cell. | 2932 // Get the value from the cell. |
| 2939 if (Serializer::enabled()) { | 2933 if (Serializer::enabled()) { |
| 2940 __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); | 2934 __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
| 2941 __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); | 2935 __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); |
| 2942 } else { | 2936 } else { |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3166 GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss); | 3160 GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss); |
| 3167 __ bind(&miss); | 3161 __ bind(&miss); |
| 3168 __ DecrementCounter(counters->keyed_load_function_prototype(), 1); | 3162 __ DecrementCounter(counters->keyed_load_function_prototype(), 1); |
| 3169 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3163 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3170 | 3164 |
| 3171 // Return the generated code. | 3165 // Return the generated code. |
| 3172 return GetCode(CALLBACKS, name); | 3166 return GetCode(CALLBACKS, name); |
| 3173 } | 3167 } |
| 3174 | 3168 |
| 3175 | 3169 |
| 3176 MaybeObject* KeyedLoadStubCompiler::CompileLoadFastElement(Map* receiver_map) { | 3170 MaybeObject* KeyedLoadStubCompiler::CompileLoadElement(Map* receiver_map) { |
| 3177 // ----------- S t a t e ------------- | 3171 // ----------- S t a t e ------------- |
| 3178 // -- eax : key | 3172 // -- eax : key |
| 3179 // -- edx : receiver | 3173 // -- edx : receiver |
| 3180 // -- esp[0] : return address | 3174 // -- esp[0] : return address |
| 3181 // ----------------------------------- | 3175 // ----------------------------------- |
| 3182 MaybeObject* maybe_stub = KeyedLoadFastElementStub().TryGetCode(); | |
| 3183 Code* stub; | 3176 Code* stub; |
| 3177 JSObject::ElementsKind elements_kind = receiver_map->elements_kind(); |
| 3178 MaybeObject* maybe_stub = KeyedLoadElementStub(elements_kind).TryGetCode(); |
| 3184 if (!maybe_stub->To(&stub)) return maybe_stub; | 3179 if (!maybe_stub->To(&stub)) return maybe_stub; |
| 3185 __ DispatchMap(edx, | 3180 __ DispatchMap(edx, |
| 3186 Handle<Map>(receiver_map), | 3181 Handle<Map>(receiver_map), |
| 3187 Handle<Code>(stub), | 3182 Handle<Code>(stub), |
| 3188 DO_SMI_CHECK); | 3183 DO_SMI_CHECK); |
| 3189 | 3184 |
| 3190 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3185 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3191 | 3186 |
| 3192 // Return the generated code. | 3187 // Return the generated code. |
| 3193 return GetCode(NORMAL, NULL); | 3188 return GetCode(NORMAL, NULL); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3238 // code for the function thereby hitting the break points. | 3233 // code for the function thereby hitting the break points. |
| 3239 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 3234 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 3240 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset)); | 3235 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset)); |
| 3241 __ cmp(ebx, factory()->undefined_value()); | 3236 __ cmp(ebx, factory()->undefined_value()); |
| 3242 __ j(not_equal, &generic_stub_call); | 3237 __ j(not_equal, &generic_stub_call); |
| 3243 #endif | 3238 #endif |
| 3244 | 3239 |
| 3245 // Load the initial map and verify that it is in fact a map. | 3240 // Load the initial map and verify that it is in fact a map. |
| 3246 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); | 3241 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); |
| 3247 // Will both indicate a NULL and a Smi. | 3242 // Will both indicate a NULL and a Smi. |
| 3248 __ test(ebx, Immediate(kSmiTagMask)); | 3243 __ JumpIfSmi(ebx, &generic_stub_call); |
| 3249 __ j(zero, &generic_stub_call); | |
| 3250 __ CmpObjectType(ebx, MAP_TYPE, ecx); | 3244 __ CmpObjectType(ebx, MAP_TYPE, ecx); |
| 3251 __ j(not_equal, &generic_stub_call); | 3245 __ j(not_equal, &generic_stub_call); |
| 3252 | 3246 |
| 3253 #ifdef DEBUG | 3247 #ifdef DEBUG |
| 3254 // Cannot construct functions this way. | 3248 // Cannot construct functions this way. |
| 3255 // edi: constructor | 3249 // edi: constructor |
| 3256 // ebx: initial map | 3250 // ebx: initial map |
| 3257 __ CmpInstanceType(ebx, JS_FUNCTION_TYPE); | 3251 __ CmpInstanceType(ebx, JS_FUNCTION_TYPE); |
| 3258 __ Assert(not_equal, "Function constructed by construct stub."); | 3252 __ Assert(not_equal, "Function constructed by construct stub."); |
| 3259 #endif | 3253 #endif |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3354 __ bind(&generic_stub_call); | 3348 __ bind(&generic_stub_call); |
| 3355 Handle<Code> generic_construct_stub = | 3349 Handle<Code> generic_construct_stub = |
| 3356 isolate()->builtins()->JSConstructStubGeneric(); | 3350 isolate()->builtins()->JSConstructStubGeneric(); |
| 3357 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); | 3351 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); |
| 3358 | 3352 |
| 3359 // Return the generated code. | 3353 // Return the generated code. |
| 3360 return GetCode(); | 3354 return GetCode(); |
| 3361 } | 3355 } |
| 3362 | 3356 |
| 3363 | 3357 |
| 3364 MaybeObject* ExternalArrayLoadStubCompiler::CompileLoad( | |
| 3365 JSObject*receiver, ExternalArrayType array_type) { | |
| 3366 // ----------- S t a t e ------------- | |
| 3367 // -- eax : key | |
| 3368 // -- edx : receiver | |
| 3369 // -- esp[0] : return address | |
| 3370 // ----------------------------------- | |
| 3371 MaybeObject* maybe_stub = | |
| 3372 KeyedLoadExternalArrayStub(array_type).TryGetCode(); | |
| 3373 Code* stub; | |
| 3374 if (!maybe_stub->To(&stub)) return maybe_stub; | |
| 3375 __ DispatchMap(edx, | |
| 3376 Handle<Map>(receiver->map()), | |
| 3377 Handle<Code>(stub), | |
| 3378 DO_SMI_CHECK); | |
| 3379 | |
| 3380 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss(); | |
| 3381 __ jmp(ic, RelocInfo::CODE_TARGET); | |
| 3382 | |
| 3383 // Return the generated code. | |
| 3384 return GetCode(); | |
| 3385 } | |
| 3386 | |
| 3387 | |
| 3388 MaybeObject* ExternalArrayStoreStubCompiler::CompileStore( | |
| 3389 JSObject* receiver, ExternalArrayType array_type) { | |
| 3390 // ----------- S t a t e ------------- | |
| 3391 // -- eax : value | |
| 3392 // -- ecx : key | |
| 3393 // -- edx : receiver | |
| 3394 // -- esp[0] : return address | |
| 3395 // ----------------------------------- | |
| 3396 MaybeObject* maybe_stub = | |
| 3397 KeyedStoreExternalArrayStub(array_type).TryGetCode(); | |
| 3398 Code* stub; | |
| 3399 if (!maybe_stub->To(&stub)) return maybe_stub; | |
| 3400 __ DispatchMap(edx, | |
| 3401 Handle<Map>(receiver->map()), | |
| 3402 Handle<Code>(stub), | |
| 3403 DO_SMI_CHECK); | |
| 3404 | |
| 3405 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); | |
| 3406 __ jmp(ic, RelocInfo::CODE_TARGET); | |
| 3407 | |
| 3408 return GetCode(); | |
| 3409 } | |
| 3410 | |
| 3411 | |
| 3412 #undef __ | 3358 #undef __ |
| 3413 #define __ ACCESS_MASM(masm) | 3359 #define __ ACCESS_MASM(masm) |
| 3414 | 3360 |
| 3415 | 3361 |
| 3416 void KeyedLoadStubCompiler::GenerateLoadExternalArray( | 3362 void KeyedLoadStubCompiler::GenerateLoadDictionaryElement( |
| 3417 MacroAssembler* masm, | 3363 MacroAssembler* masm) { |
| 3418 ExternalArrayType array_type) { | |
| 3419 // ----------- S t a t e ------------- | 3364 // ----------- S t a t e ------------- |
| 3420 // -- eax : key | 3365 // -- eax : key |
| 3421 // -- edx : receiver | 3366 // -- edx : receiver |
| 3367 // -- esp[0] : return address |
| 3368 // ----------------------------------- |
| 3369 Label slow, miss_force_generic; |
| 3370 |
| 3371 // This stub is meant to be tail-jumped to, the receiver must already |
| 3372 // have been verified by the caller to not be a smi. |
| 3373 __ JumpIfNotSmi(eax, &miss_force_generic); |
| 3374 __ mov(ebx, eax); |
| 3375 __ SmiUntag(ebx); |
| 3376 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3377 |
| 3378 // Push receiver on the stack to free up a register for the dictionary |
| 3379 // probing. |
| 3380 __ push(edx); |
| 3381 __ LoadFromNumberDictionary(&slow, |
| 3382 ecx, |
| 3383 eax, |
| 3384 ebx, |
| 3385 edx, |
| 3386 edi, |
| 3387 eax); |
| 3388 // Pop receiver before returning. |
| 3389 __ pop(edx); |
| 3390 __ ret(0); |
| 3391 |
| 3392 __ bind(&slow); |
| 3393 __ pop(edx); |
| 3394 |
| 3395 // ----------- S t a t e ------------- |
| 3396 // -- eax : value |
| 3397 // -- ecx : key |
| 3398 // -- edx : receiver |
| 3399 // -- esp[0] : return address |
| 3400 // ----------------------------------- |
| 3401 |
| 3402 Handle<Code> slow_ic = |
| 3403 masm->isolate()->builtins()->KeyedLoadIC_Slow(); |
| 3404 __ jmp(slow_ic, RelocInfo::CODE_TARGET); |
| 3405 |
| 3406 __ bind(&miss_force_generic); |
| 3407 // ----------- S t a t e ------------- |
| 3408 // -- eax : value |
| 3409 // -- ecx : key |
| 3410 // -- edx : receiver |
| 3411 // -- esp[0] : return address |
| 3412 // ----------------------------------- |
| 3413 |
| 3414 Handle<Code> miss_force_generic_ic = |
| 3415 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); |
| 3416 __ jmp(miss_force_generic_ic, RelocInfo::CODE_TARGET); |
| 3417 } |
| 3418 |
| 3419 |
| 3420 void KeyedLoadStubCompiler::GenerateLoadExternalArray( |
| 3421 MacroAssembler* masm, |
| 3422 JSObject::ElementsKind elements_kind) { |
| 3423 // ----------- S t a t e ------------- |
| 3424 // -- eax : key |
| 3425 // -- edx : receiver |
| 3422 // -- esp[0] : return address | 3426 // -- esp[0] : return address |
| 3423 // ----------------------------------- | 3427 // ----------------------------------- |
| 3424 Label miss_force_generic, failed_allocation, slow; | 3428 Label miss_force_generic, failed_allocation, slow; |
| 3425 | 3429 |
| 3426 // This stub is meant to be tail-jumped to, the receiver must already | 3430 // This stub is meant to be tail-jumped to, the receiver must already |
| 3427 // have been verified by the caller to not be a smi. | 3431 // have been verified by the caller to not be a smi. |
| 3428 | 3432 |
| 3429 // Check that the key is a smi. | 3433 // Check that the key is a smi. |
| 3430 __ test(eax, Immediate(kSmiTagMask)); | 3434 __ JumpIfNotSmi(eax, &miss_force_generic); |
| 3431 __ j(not_zero, &miss_force_generic); | |
| 3432 | 3435 |
| 3433 // Check that the index is in range. | 3436 // Check that the index is in range. |
| 3434 __ mov(ecx, eax); | 3437 __ mov(ecx, eax); |
| 3435 __ SmiUntag(ecx); // Untag the index. | 3438 __ SmiUntag(ecx); // Untag the index. |
| 3436 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); | 3439 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3437 __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset)); | 3440 __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset)); |
| 3438 // Unsigned comparison catches both negative and too-large values. | 3441 // Unsigned comparison catches both negative and too-large values. |
| 3439 __ j(above_equal, &miss_force_generic); | 3442 __ j(above_equal, &miss_force_generic); |
| 3440 __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset)); | 3443 __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset)); |
| 3441 // ebx: base pointer of external storage | 3444 // ebx: base pointer of external storage |
| 3442 switch (array_type) { | 3445 switch (elements_kind) { |
| 3443 case kExternalByteArray: | 3446 case JSObject::EXTERNAL_BYTE_ELEMENTS: |
| 3444 __ movsx_b(eax, Operand(ebx, ecx, times_1, 0)); | 3447 __ movsx_b(eax, Operand(ebx, ecx, times_1, 0)); |
| 3445 break; | 3448 break; |
| 3446 case kExternalUnsignedByteArray: | 3449 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 3447 case kExternalPixelArray: | 3450 case JSObject::EXTERNAL_PIXEL_ELEMENTS: |
| 3448 __ movzx_b(eax, Operand(ebx, ecx, times_1, 0)); | 3451 __ movzx_b(eax, Operand(ebx, ecx, times_1, 0)); |
| 3449 break; | 3452 break; |
| 3450 case kExternalShortArray: | 3453 case JSObject::EXTERNAL_SHORT_ELEMENTS: |
| 3451 __ movsx_w(eax, Operand(ebx, ecx, times_2, 0)); | 3454 __ movsx_w(eax, Operand(ebx, ecx, times_2, 0)); |
| 3452 break; | 3455 break; |
| 3453 case kExternalUnsignedShortArray: | 3456 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 3454 __ movzx_w(eax, Operand(ebx, ecx, times_2, 0)); | 3457 __ movzx_w(eax, Operand(ebx, ecx, times_2, 0)); |
| 3455 break; | 3458 break; |
| 3456 case kExternalIntArray: | 3459 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 3457 case kExternalUnsignedIntArray: | 3460 case JSObject::EXTERNAL_INT_ELEMENTS: |
| 3458 __ mov(ecx, Operand(ebx, ecx, times_4, 0)); | 3461 __ mov(ecx, Operand(ebx, ecx, times_4, 0)); |
| 3459 break; | 3462 break; |
| 3460 case kExternalFloatArray: | 3463 case JSObject::EXTERNAL_FLOAT_ELEMENTS: |
| 3461 __ fld_s(Operand(ebx, ecx, times_4, 0)); | 3464 __ fld_s(Operand(ebx, ecx, times_4, 0)); |
| 3462 break; | 3465 break; |
| 3463 case kExternalDoubleArray: | 3466 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: |
| 3464 __ fld_d(Operand(ebx, ecx, times_8, 0)); | 3467 __ fld_d(Operand(ebx, ecx, times_8, 0)); |
| 3465 break; | 3468 break; |
| 3466 default: | 3469 default: |
| 3467 UNREACHABLE(); | 3470 UNREACHABLE(); |
| 3468 break; | 3471 break; |
| 3469 } | 3472 } |
| 3470 | 3473 |
| 3471 // For integer array types: | 3474 // For integer array types: |
| 3472 // ecx: value | 3475 // ecx: value |
| 3473 // For floating-point array type: | 3476 // For floating-point array type: |
| 3474 // FP(0): value | 3477 // FP(0): value |
| 3475 | 3478 |
| 3476 if (array_type == kExternalIntArray || | 3479 if (elements_kind == JSObject::EXTERNAL_INT_ELEMENTS || |
| 3477 array_type == kExternalUnsignedIntArray) { | 3480 elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) { |
| 3478 // For the Int and UnsignedInt array types, we need to see whether | 3481 // For the Int and UnsignedInt array types, we need to see whether |
| 3479 // the value can be represented in a Smi. If not, we need to convert | 3482 // the value can be represented in a Smi. If not, we need to convert |
| 3480 // it to a HeapNumber. | 3483 // it to a HeapNumber. |
| 3481 Label box_int; | 3484 Label box_int; |
| 3482 if (array_type == kExternalIntArray) { | 3485 if (elements_kind == JSObject::EXTERNAL_INT_ELEMENTS) { |
| 3483 __ cmp(ecx, 0xC0000000); | 3486 __ cmp(ecx, 0xC0000000); |
| 3484 __ j(sign, &box_int); | 3487 __ j(sign, &box_int); |
| 3485 } else { | 3488 } else { |
| 3486 ASSERT_EQ(array_type, kExternalUnsignedIntArray); | 3489 ASSERT_EQ(JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind); |
| 3487 // The test is different for unsigned int values. Since we need | 3490 // The test is different for unsigned int values. Since we need |
| 3488 // the value to be in the range of a positive smi, we can't | 3491 // the value to be in the range of a positive smi, we can't |
| 3489 // handle either of the top two bits being set in the value. | 3492 // handle either of the top two bits being set in the value. |
| 3490 __ test(ecx, Immediate(0xC0000000)); | 3493 __ test(ecx, Immediate(0xC0000000)); |
| 3491 __ j(not_zero, &box_int); | 3494 __ j(not_zero, &box_int); |
| 3492 } | 3495 } |
| 3493 | 3496 |
| 3494 __ mov(eax, ecx); | 3497 __ mov(eax, ecx); |
| 3495 __ SmiTag(eax); | 3498 __ SmiTag(eax); |
| 3496 __ ret(0); | 3499 __ ret(0); |
| 3497 | 3500 |
| 3498 __ bind(&box_int); | 3501 __ bind(&box_int); |
| 3499 | 3502 |
| 3500 // Allocate a HeapNumber for the int and perform int-to-double | 3503 // Allocate a HeapNumber for the int and perform int-to-double |
| 3501 // conversion. | 3504 // conversion. |
| 3502 if (array_type == kExternalIntArray) { | 3505 if (elements_kind == JSObject::EXTERNAL_INT_ELEMENTS) { |
| 3503 __ push(ecx); | 3506 __ push(ecx); |
| 3504 __ fild_s(Operand(esp, 0)); | 3507 __ fild_s(Operand(esp, 0)); |
| 3505 __ pop(ecx); | 3508 __ pop(ecx); |
| 3506 } else { | 3509 } else { |
| 3507 ASSERT(array_type == kExternalUnsignedIntArray); | 3510 ASSERT_EQ(JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind); |
| 3508 // Need to zero-extend the value. | 3511 // Need to zero-extend the value. |
| 3509 // There's no fild variant for unsigned values, so zero-extend | 3512 // There's no fild variant for unsigned values, so zero-extend |
| 3510 // to a 64-bit int manually. | 3513 // to a 64-bit int manually. |
| 3511 __ push(Immediate(0)); | 3514 __ push(Immediate(0)); |
| 3512 __ push(ecx); | 3515 __ push(ecx); |
| 3513 __ fild_d(Operand(esp, 0)); | 3516 __ fild_d(Operand(esp, 0)); |
| 3514 __ pop(ecx); | 3517 __ pop(ecx); |
| 3515 __ pop(ecx); | 3518 __ pop(ecx); |
| 3516 } | 3519 } |
| 3517 // FP(0): value | 3520 // FP(0): value |
| 3518 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); | 3521 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); |
| 3519 // Set the value. | 3522 // Set the value. |
| 3520 __ mov(eax, ecx); | 3523 __ mov(eax, ecx); |
| 3521 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 3524 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3522 __ ret(0); | 3525 __ ret(0); |
| 3523 } else if (array_type == kExternalFloatArray || | 3526 } else if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS || |
| 3524 array_type == kExternalDoubleArray) { | 3527 elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) { |
| 3525 // For the floating-point array type, we need to always allocate a | 3528 // For the floating-point array type, we need to always allocate a |
| 3526 // HeapNumber. | 3529 // HeapNumber. |
| 3527 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); | 3530 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); |
| 3528 // Set the value. | 3531 // Set the value. |
| 3529 __ mov(eax, ecx); | 3532 __ mov(eax, ecx); |
| 3530 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 3533 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3531 __ ret(0); | 3534 __ ret(0); |
| 3532 } else { | 3535 } else { |
| 3533 __ SmiTag(eax); | 3536 __ SmiTag(eax); |
| 3534 __ ret(0); | 3537 __ ret(0); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 3564 // Miss case: Jump to runtime. | 3567 // Miss case: Jump to runtime. |
| 3565 __ bind(&miss_force_generic); | 3568 __ bind(&miss_force_generic); |
| 3566 Handle<Code> miss_ic = | 3569 Handle<Code> miss_ic = |
| 3567 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); | 3570 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); |
| 3568 __ jmp(miss_ic, RelocInfo::CODE_TARGET); | 3571 __ jmp(miss_ic, RelocInfo::CODE_TARGET); |
| 3569 } | 3572 } |
| 3570 | 3573 |
| 3571 | 3574 |
| 3572 void KeyedStoreStubCompiler::GenerateStoreExternalArray( | 3575 void KeyedStoreStubCompiler::GenerateStoreExternalArray( |
| 3573 MacroAssembler* masm, | 3576 MacroAssembler* masm, |
| 3574 ExternalArrayType array_type) { | 3577 JSObject::ElementsKind elements_kind) { |
| 3575 // ----------- S t a t e ------------- | 3578 // ----------- S t a t e ------------- |
| 3576 // -- eax : key | 3579 // -- eax : key |
| 3577 // -- edx : receiver | 3580 // -- edx : receiver |
| 3578 // -- esp[0] : return address | 3581 // -- esp[0] : return address |
| 3579 // ----------------------------------- | 3582 // ----------------------------------- |
| 3580 Label miss_force_generic, slow, check_heap_number; | 3583 Label miss_force_generic, slow, check_heap_number; |
| 3581 | 3584 |
| 3582 // This stub is meant to be tail-jumped to, the receiver must already | 3585 // This stub is meant to be tail-jumped to, the receiver must already |
| 3583 // have been verified by the caller to not be a smi. | 3586 // have been verified by the caller to not be a smi. |
| 3584 | 3587 |
| 3585 // Check that the key is a smi. | 3588 // Check that the key is a smi. |
| 3586 __ test(ecx, Immediate(kSmiTagMask)); | 3589 __ JumpIfNotSmi(ecx, &miss_force_generic); |
| 3587 __ j(not_zero, &miss_force_generic); | |
| 3588 | 3590 |
| 3589 // Check that the index is in range. | 3591 // Check that the index is in range. |
| 3590 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | 3592 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3591 __ mov(ebx, ecx); | 3593 __ mov(ebx, ecx); |
| 3592 __ SmiUntag(ebx); | 3594 __ SmiUntag(ebx); |
| 3593 __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset)); | 3595 __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset)); |
| 3594 // Unsigned comparison catches both negative and too-large values. | 3596 // Unsigned comparison catches both negative and too-large values. |
| 3595 __ j(above_equal, &slow); | 3597 __ j(above_equal, &slow); |
| 3596 | 3598 |
| 3597 // Handle both smis and HeapNumbers in the fast path. Go to the | 3599 // Handle both smis and HeapNumbers in the fast path. Go to the |
| 3598 // runtime for all other kinds of values. | 3600 // runtime for all other kinds of values. |
| 3599 // eax: value | 3601 // eax: value |
| 3600 // edx: receiver | 3602 // edx: receiver |
| 3601 // ecx: key | 3603 // ecx: key |
| 3602 // edi: elements array | 3604 // edi: elements array |
| 3603 // ebx: untagged index | 3605 // ebx: untagged index |
| 3604 __ test(eax, Immediate(kSmiTagMask)); | 3606 if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) { |
| 3605 if (array_type == kExternalPixelArray) | 3607 __ JumpIfNotSmi(eax, &slow); |
| 3606 __ j(not_equal, &slow); | 3608 } else { |
| 3607 else | 3609 __ JumpIfNotSmi(eax, &check_heap_number); |
| 3608 __ j(not_equal, &check_heap_number); | 3610 } |
| 3609 | 3611 |
| 3610 // smi case | 3612 // smi case |
| 3611 __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed. | 3613 __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed. |
| 3612 __ SmiUntag(ecx); | 3614 __ SmiUntag(ecx); |
| 3613 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); | 3615 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); |
| 3614 // ecx: base pointer of external storage | 3616 // ecx: base pointer of external storage |
| 3615 switch (array_type) { | 3617 switch (elements_kind) { |
| 3616 case kExternalPixelArray: | 3618 case JSObject::EXTERNAL_PIXEL_ELEMENTS: |
| 3617 { // Clamp the value to [0..255]. | 3619 { // Clamp the value to [0..255]. |
| 3618 Label done; | 3620 Label done; |
| 3619 __ test(ecx, Immediate(0xFFFFFF00)); | 3621 __ test(ecx, Immediate(0xFFFFFF00)); |
| 3620 __ j(zero, &done, Label::kNear); | 3622 __ j(zero, &done, Label::kNear); |
| 3621 __ setcc(negative, ecx); // 1 if negative, 0 if positive. | 3623 __ setcc(negative, ecx); // 1 if negative, 0 if positive. |
| 3622 __ dec_b(ecx); // 0 if negative, 255 if positive. | 3624 __ dec_b(ecx); // 0 if negative, 255 if positive. |
| 3623 __ bind(&done); | 3625 __ bind(&done); |
| 3624 } | 3626 } |
| 3625 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); | 3627 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3626 break; | 3628 break; |
| 3627 case kExternalByteArray: | 3629 case JSObject::EXTERNAL_BYTE_ELEMENTS: |
| 3628 case kExternalUnsignedByteArray: | 3630 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 3629 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); | 3631 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3630 break; | 3632 break; |
| 3631 case kExternalShortArray: | 3633 case JSObject::EXTERNAL_SHORT_ELEMENTS: |
| 3632 case kExternalUnsignedShortArray: | 3634 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 3633 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); | 3635 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); |
| 3634 break; | 3636 break; |
| 3635 case kExternalIntArray: | 3637 case JSObject::EXTERNAL_INT_ELEMENTS: |
| 3636 case kExternalUnsignedIntArray: | 3638 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 3637 __ mov(Operand(edi, ebx, times_4, 0), ecx); | 3639 __ mov(Operand(edi, ebx, times_4, 0), ecx); |
| 3638 break; | 3640 break; |
| 3639 case kExternalFloatArray: | 3641 case JSObject::EXTERNAL_FLOAT_ELEMENTS: |
| 3640 case kExternalDoubleArray: | 3642 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: |
| 3641 // Need to perform int-to-float conversion. | 3643 // Need to perform int-to-float conversion. |
| 3642 __ push(ecx); | 3644 __ push(ecx); |
| 3643 __ fild_s(Operand(esp, 0)); | 3645 __ fild_s(Operand(esp, 0)); |
| 3644 __ pop(ecx); | 3646 __ pop(ecx); |
| 3645 if (array_type == kExternalFloatArray) { | 3647 if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { |
| 3646 __ fstp_s(Operand(edi, ebx, times_4, 0)); | 3648 __ fstp_s(Operand(edi, ebx, times_4, 0)); |
| 3647 } else { // array_type == kExternalDoubleArray. | 3649 } else { // elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS. |
| 3648 __ fstp_d(Operand(edi, ebx, times_8, 0)); | 3650 __ fstp_d(Operand(edi, ebx, times_8, 0)); |
| 3649 } | 3651 } |
| 3650 break; | 3652 break; |
| 3651 default: | 3653 default: |
| 3652 UNREACHABLE(); | 3654 UNREACHABLE(); |
| 3653 break; | 3655 break; |
| 3654 } | 3656 } |
| 3655 __ ret(0); // Return the original value. | 3657 __ ret(0); // Return the original value. |
| 3656 | 3658 |
| 3657 // TODO(danno): handle heap number -> pixel array conversion | 3659 // TODO(danno): handle heap number -> pixel array conversion |
| 3658 if (array_type != kExternalPixelArray) { | 3660 if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) { |
| 3659 __ bind(&check_heap_number); | 3661 __ bind(&check_heap_number); |
| 3660 // eax: value | 3662 // eax: value |
| 3661 // edx: receiver | 3663 // edx: receiver |
| 3662 // ecx: key | 3664 // ecx: key |
| 3663 // edi: elements array | 3665 // edi: elements array |
| 3664 // ebx: untagged index | 3666 // ebx: untagged index |
| 3665 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 3667 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 3666 Immediate(masm->isolate()->factory()->heap_number_map())); | 3668 Immediate(masm->isolate()->factory()->heap_number_map())); |
| 3667 __ j(not_equal, &slow); | 3669 __ j(not_equal, &slow); |
| 3668 | 3670 |
| 3669 // The WebGL specification leaves the behavior of storing NaN and | 3671 // The WebGL specification leaves the behavior of storing NaN and |
| 3670 // +/-Infinity into integer arrays basically undefined. For more | 3672 // +/-Infinity into integer arrays basically undefined. For more |
| 3671 // reproducible behavior, convert these to zero. | 3673 // reproducible behavior, convert these to zero. |
| 3672 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); | 3674 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); |
| 3673 // ebx: untagged index | 3675 // ebx: untagged index |
| 3674 // edi: base pointer of external storage | 3676 // edi: base pointer of external storage |
| 3675 if (array_type == kExternalFloatArray) { | 3677 if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { |
| 3676 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 3678 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3677 __ fstp_s(Operand(edi, ebx, times_4, 0)); | 3679 __ fstp_s(Operand(edi, ebx, times_4, 0)); |
| 3678 __ ret(0); | 3680 __ ret(0); |
| 3679 } else if (array_type == kExternalDoubleArray) { | 3681 } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) { |
| 3680 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 3682 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3681 __ fstp_d(Operand(edi, ebx, times_8, 0)); | 3683 __ fstp_d(Operand(edi, ebx, times_8, 0)); |
| 3682 __ ret(0); | 3684 __ ret(0); |
| 3683 } else { | 3685 } else { |
| 3684 // Perform float-to-int conversion with truncation (round-to-zero) | 3686 // Perform float-to-int conversion with truncation (round-to-zero) |
| 3685 // behavior. | 3687 // behavior. |
| 3686 | 3688 |
| 3687 // For the moment we make the slow call to the runtime on | 3689 // For the moment we make the slow call to the runtime on |
| 3688 // processors that don't support SSE2. The code in IntegerConvert | 3690 // processors that don't support SSE2. The code in IntegerConvert |
| 3689 // (code-stubs-ia32.cc) is roughly what is needed here though the | 3691 // (code-stubs-ia32.cc) is roughly what is needed here though the |
| 3690 // conversion failure case does not need to be handled. | 3692 // conversion failure case does not need to be handled. |
| 3691 if (CpuFeatures::IsSupported(SSE2)) { | 3693 if (CpuFeatures::IsSupported(SSE2)) { |
| 3692 if (array_type != kExternalIntArray && | 3694 if (elements_kind != JSObject::EXTERNAL_INT_ELEMENTS && |
| 3693 array_type != kExternalUnsignedIntArray) { | 3695 elements_kind != JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) { |
| 3694 ASSERT(CpuFeatures::IsSupported(SSE2)); | 3696 ASSERT(CpuFeatures::IsSupported(SSE2)); |
| 3695 CpuFeatures::Scope scope(SSE2); | 3697 CpuFeatures::Scope scope(SSE2); |
| 3696 __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset)); | 3698 __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3697 // ecx: untagged integer value | 3699 // ecx: untagged integer value |
| 3698 switch (array_type) { | 3700 switch (elements_kind) { |
| 3699 case kExternalPixelArray: | 3701 case JSObject::EXTERNAL_PIXEL_ELEMENTS: |
| 3700 { // Clamp the value to [0..255]. | 3702 { // Clamp the value to [0..255]. |
| 3701 Label done; | 3703 Label done; |
| 3702 __ test(ecx, Immediate(0xFFFFFF00)); | 3704 __ test(ecx, Immediate(0xFFFFFF00)); |
| 3703 __ j(zero, &done, Label::kNear); | 3705 __ j(zero, &done, Label::kNear); |
| 3704 __ setcc(negative, ecx); // 1 if negative, 0 if positive. | 3706 __ setcc(negative, ecx); // 1 if negative, 0 if positive. |
| 3705 __ dec_b(ecx); // 0 if negative, 255 if positive. | 3707 __ dec_b(ecx); // 0 if negative, 255 if positive. |
| 3706 __ bind(&done); | 3708 __ bind(&done); |
| 3707 } | 3709 } |
| 3708 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); | 3710 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3709 break; | 3711 break; |
| 3710 case kExternalByteArray: | 3712 case JSObject::EXTERNAL_BYTE_ELEMENTS: |
| 3711 case kExternalUnsignedByteArray: | 3713 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 3712 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); | 3714 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3713 break; | 3715 break; |
| 3714 case kExternalShortArray: | 3716 case JSObject::EXTERNAL_SHORT_ELEMENTS: |
| 3715 case kExternalUnsignedShortArray: | 3717 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 3716 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); | 3718 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); |
| 3717 break; | 3719 break; |
| 3718 default: | 3720 default: |
| 3719 UNREACHABLE(); | 3721 UNREACHABLE(); |
| 3720 break; | 3722 break; |
| 3721 } | 3723 } |
| 3722 } else { | 3724 } else { |
| 3723 if (CpuFeatures::IsSupported(SSE3)) { | 3725 if (CpuFeatures::IsSupported(SSE3)) { |
| 3724 CpuFeatures::Scope scope(SSE3); | 3726 CpuFeatures::Scope scope(SSE3); |
| 3725 // fisttp stores values as signed integers. To represent the | 3727 // fisttp stores values as signed integers. To represent the |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3778 // -- esp[0] : return address | 3780 // -- esp[0] : return address |
| 3779 // ----------------------------------- | 3781 // ----------------------------------- |
| 3780 | 3782 |
| 3781 __ bind(&miss_force_generic); | 3783 __ bind(&miss_force_generic); |
| 3782 Handle<Code> miss_ic = | 3784 Handle<Code> miss_ic = |
| 3783 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); | 3785 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); |
| 3784 __ jmp(miss_ic, RelocInfo::CODE_TARGET); | 3786 __ jmp(miss_ic, RelocInfo::CODE_TARGET); |
| 3785 } | 3787 } |
| 3786 | 3788 |
| 3787 | 3789 |
| 3788 | |
| 3789 | |
| 3790 void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) { | 3790 void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) { |
| 3791 // ----------- S t a t e ------------- | 3791 // ----------- S t a t e ------------- |
| 3792 // -- eax : key | 3792 // -- eax : key |
| 3793 // -- edx : receiver | 3793 // -- edx : receiver |
| 3794 // -- esp[0] : return address | 3794 // -- esp[0] : return address |
| 3795 // ----------------------------------- | 3795 // ----------------------------------- |
| 3796 Label miss_force_generic; | 3796 Label miss_force_generic; |
| 3797 | 3797 |
| 3798 // This stub is meant to be tail-jumped to, the receiver must already | 3798 // This stub is meant to be tail-jumped to, the receiver must already |
| 3799 // have been verified by the caller to not be a smi. | 3799 // have been verified by the caller to not be a smi. |
| 3800 | 3800 |
| 3801 // Check that the key is a smi. | 3801 // Check that the key is a smi. |
| 3802 __ test(eax, Immediate(kSmiTagMask)); | 3802 __ JumpIfNotSmi(eax, &miss_force_generic); |
| 3803 __ j(not_zero, &miss_force_generic); | |
| 3804 | 3803 |
| 3805 // Get the elements array. | 3804 // Get the elements array. |
| 3806 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); | 3805 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3807 __ AssertFastElements(ecx); | 3806 __ AssertFastElements(ecx); |
| 3808 | 3807 |
| 3809 // Check that the key is within bounds. | 3808 // Check that the key is within bounds. |
| 3810 __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset)); | 3809 __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset)); |
| 3811 __ j(above_equal, &miss_force_generic); | 3810 __ j(above_equal, &miss_force_generic); |
| 3812 | 3811 |
| 3813 // Load the result and make sure it's not the hole. | 3812 // Load the result and make sure it's not the hole. |
| 3814 __ mov(ebx, Operand(ecx, eax, times_2, | 3813 __ mov(ebx, Operand(ecx, eax, times_2, |
| 3815 FixedArray::kHeaderSize - kHeapObjectTag)); | 3814 FixedArray::kHeaderSize - kHeapObjectTag)); |
| 3816 __ cmp(ebx, masm->isolate()->factory()->the_hole_value()); | 3815 __ cmp(ebx, masm->isolate()->factory()->the_hole_value()); |
| 3817 __ j(equal, &miss_force_generic); | 3816 __ j(equal, &miss_force_generic); |
| 3818 __ mov(eax, ebx); | 3817 __ mov(eax, ebx); |
| 3819 __ ret(0); | 3818 __ ret(0); |
| 3820 | 3819 |
| 3821 __ bind(&miss_force_generic); | 3820 __ bind(&miss_force_generic); |
| 3822 Handle<Code> miss_ic = | 3821 Handle<Code> miss_ic = |
| 3823 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); | 3822 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); |
| 3824 __ jmp(miss_ic, RelocInfo::CODE_TARGET); | 3823 __ jmp(miss_ic, RelocInfo::CODE_TARGET); |
| 3825 } | 3824 } |
| 3826 | 3825 |
| 3827 | 3826 |
| 3828 void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, | 3827 void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, |
| 3829 bool is_js_array) { | 3828 bool is_js_array) { |
| 3830 // ----------- S t a t e ------------- | 3829 // ----------- S t a t e ------------- |
| 3831 // -- eax : key | 3830 // -- eax : value |
| 3831 // -- ecx : key |
| 3832 // -- edx : receiver | 3832 // -- edx : receiver |
| 3833 // -- esp[0] : return address | 3833 // -- esp[0] : return address |
| 3834 // ----------------------------------- | 3834 // ----------------------------------- |
| 3835 Label miss_force_generic; | 3835 Label miss_force_generic; |
| 3836 | 3836 |
| 3837 // This stub is meant to be tail-jumped to, the receiver must already | 3837 // This stub is meant to be tail-jumped to, the receiver must already |
| 3838 // have been verified by the caller to not be a smi. | 3838 // have been verified by the caller to not be a smi. |
| 3839 | 3839 |
| 3840 // Check that the key is a smi. | 3840 // Check that the key is a smi. |
| 3841 __ test(ecx, Immediate(kSmiTagMask)); | 3841 __ JumpIfNotSmi(ecx, &miss_force_generic); |
| 3842 __ j(not_zero, &miss_force_generic); | |
| 3843 | 3842 |
| 3844 // Get the elements array and make sure it is a fast element array, not 'cow'. | 3843 // Get the elements array and make sure it is a fast element array, not 'cow'. |
| 3845 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | 3844 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3846 __ cmp(FieldOperand(edi, HeapObject::kMapOffset), | 3845 __ cmp(FieldOperand(edi, HeapObject::kMapOffset), |
| 3847 Immediate(masm->isolate()->factory()->fixed_array_map())); | 3846 Immediate(masm->isolate()->factory()->fixed_array_map())); |
| 3848 __ j(not_equal, &miss_force_generic); | 3847 __ j(not_equal, &miss_force_generic); |
| 3849 | 3848 |
| 3850 if (is_js_array) { | 3849 if (is_js_array) { |
| 3851 // Check that the key is within bounds. | 3850 // Check that the key is within bounds. |
| 3852 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis. | 3851 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 3873 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); | 3872 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); |
| 3874 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); | 3873 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); |
| 3875 } | 3874 } |
| 3876 | 3875 |
| 3877 | 3876 |
| 3878 #undef __ | 3877 #undef __ |
| 3879 | 3878 |
| 3880 } } // namespace v8::internal | 3879 } } // namespace v8::internal |
| 3881 | 3880 |
| 3882 #endif // V8_TARGET_ARCH_IA32 | 3881 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |