diff options
Diffstat (limited to 'deps/v8/src/x64/stub-cache-x64.cc')
-rw-r--r-- | deps/v8/src/x64/stub-cache-x64.cc | 1591 |
1 files changed, 719 insertions, 872 deletions
diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc index 76d255579..5a81c8974 100644 --- a/deps/v8/src/x64/stub-cache-x64.cc +++ b/deps/v8/src/x64/stub-cache-x64.cc @@ -82,13 +82,12 @@ static void ProbeTable(Isolate* isolate, // must always call a backup property check that is complete. // This function is safe to call if the receiver has fast properties. // Name must be a symbol and receiver must be a heap object. -MUST_USE_RESULT static MaybeObject* GenerateDictionaryNegativeLookup( - MacroAssembler* masm, - Label* miss_label, - Register receiver, - String* name, - Register r0, - Register r1) { +static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, + Label* miss_label, + Register receiver, + Handle<String> name, + Register r0, + Register r1) { ASSERT(name->IsSymbol()); Counters* counters = masm->isolate()->counters(); __ IncrementCounter(counters->negative_lookups(), 1); @@ -118,19 +117,14 @@ MUST_USE_RESULT static MaybeObject* GenerateDictionaryNegativeLookup( __ j(not_equal, miss_label); Label done; - MaybeObject* result = StringDictionaryLookupStub::GenerateNegativeLookup( - masm, - miss_label, - &done, - properties, - name, - r1); - if (result->IsFailure()) return result; - + StringDictionaryLookupStub::GenerateNegativeLookup(masm, + miss_label, + &done, + properties, + name, + r1); __ bind(&done); __ DecrementCounter(counters->negative_lookups_miss(), 1); - - return result; } @@ -211,7 +205,10 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( - MacroAssembler* masm, int index, Register prototype, Label* miss) { + MacroAssembler* masm, + int index, + Register prototype, + Label* miss) { Isolate* isolate = masm->isolate(); // Check we're still in the same context. __ Move(prototype, isolate->global()); @@ -219,8 +216,8 @@ void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( prototype); __ j(not_equal, miss); // Get the global function with the given index. - JSFunction* function = - JSFunction::cast(isolate->global_context()->get(index)); + Handle<JSFunction> function( + JSFunction::cast(isolate->global_context()->get(index))); // Load its initial map. The global functions all have initial maps. __ Move(prototype, Handle<Map>(function->initial_map())); // Load the prototype from the initial map. @@ -312,8 +309,10 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, // are loaded directly otherwise the property is loaded from the properties // fixed array. void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, - Register dst, Register src, - JSObject* holder, int index) { + Register dst, + Register src, + Handle<JSObject> holder, + int index) { // Adjust for the number of properties stored in the holder. index -= holder->map()->inobject_properties(); if (index < 0) { @@ -333,11 +332,11 @@ static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, Register holder, Register name, - JSObject* holder_obj) { + Handle<JSObject> holder_obj) { __ push(name); - InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor(); - ASSERT(!masm->isolate()->heap()->InNewSpace(interceptor)); - __ Move(kScratchRegister, Handle<Object>(interceptor)); + Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); + ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor)); + __ Move(kScratchRegister, interceptor); __ push(kScratchRegister); __ push(receiver); __ push(holder); @@ -345,11 +344,12 @@ static void PushInterceptorArguments(MacroAssembler* masm, } -static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm, - Register receiver, - Register holder, - Register name, - JSObject* holder_obj) { +static void CompileCallLoadPropertyWithInterceptor( + MacroAssembler* masm, + Register receiver, + Register holder, + Register name, + Handle<JSObject> holder_obj) { PushInterceptorArguments(masm, receiver, holder, name, holder_obj); ExternalReference ref = @@ -403,9 +403,9 @@ static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { // Generates call to API function. -static MaybeObject* GenerateFastApiCall(MacroAssembler* masm, - const CallOptimization& optimization, - int argc) { +static void GenerateFastApiCall(MacroAssembler* masm, + const CallOptimization& optimization, + int argc) { // ----------- S t a t e ------------- // -- rsp[0] : return address // -- rsp[8] : object passing the type check @@ -420,29 +420,25 @@ static MaybeObject* GenerateFastApiCall(MacroAssembler* masm, // -- rsp[(argc + 4) * 8] : receiver // ----------------------------------- // Get the function and setup the context. - JSFunction* function = optimization.constant_function(); - __ Move(rdi, Handle<JSFunction>(function)); + Handle<JSFunction> function = optimization.constant_function(); + __ Move(rdi, function); __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); // Pass the additional arguments. __ movq(Operand(rsp, 2 * kPointerSize), rdi); - Object* call_data = optimization.api_call_info()->data(); - Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info()); - if (masm->isolate()->heap()->InNewSpace(call_data)) { - __ Move(rcx, api_call_info_handle); + Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); + Handle<Object> call_data(api_call_info->data()); + if (masm->isolate()->heap()->InNewSpace(*call_data)) { + __ Move(rcx, api_call_info); __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset)); __ movq(Operand(rsp, 3 * kPointerSize), rbx); } else { - __ Move(Operand(rsp, 3 * kPointerSize), Handle<Object>(call_data)); + __ Move(Operand(rsp, 3 * kPointerSize), call_data); } // Prepare arguments. __ lea(rbx, Operand(rsp, 3 * kPointerSize)); - Object* callback = optimization.api_call_info()->callback(); - Address api_function_address = v8::ToCData<Address>(callback); - ApiFunction fun(api_function_address); - #ifdef _WIN64 // Win64 uses first register--rcx--for returned value. Register arguments_arg = rdx; @@ -465,12 +461,11 @@ static MaybeObject* GenerateFastApiCall(MacroAssembler* masm, // v8::InvocationCallback's argument. __ lea(arguments_arg, StackSpaceOperand(0)); - // Emitting a stub call may try to allocate (if the code is not - // already generated). Do not allow the assembler to perform a - // garbage collection but instead return the allocation failure - // object. - return masm->TryCallApiFunctionAndReturn(&fun, - argc + kFastApiCallArguments + 1); + + // Function address is a foreign pointer outside V8's heap. + Address function_address = v8::ToCData<Address>(api_call_info->callback()); + __ CallApiFunctionAndReturn(function_address, + argc + kFastApiCallArguments + 1); } @@ -485,16 +480,16 @@ class CallInterceptorCompiler BASE_EMBEDDED { name_(name), extra_ic_state_(extra_ic_state) {} - MaybeObject* Compile(MacroAssembler* masm, - JSObject* object, - JSObject* holder, - String* name, - LookupResult* lookup, - Register receiver, - Register scratch1, - Register scratch2, - Register scratch3, - Label* miss) { + void Compile(MacroAssembler* masm, + Handle<JSObject> object, + Handle<JSObject> holder, + Handle<String> name, + LookupResult* lookup, + Register receiver, + Register scratch1, + Register scratch2, + Register scratch3, + Label* miss) { ASSERT(holder->HasNamedInterceptor()); ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); @@ -502,45 +497,27 @@ class CallInterceptorCompiler BASE_EMBEDDED { __ JumpIfSmi(receiver, miss); CallOptimization optimization(lookup); - if (optimization.is_constant_call()) { - return CompileCacheable(masm, - object, - receiver, - scratch1, - scratch2, - scratch3, - holder, - lookup, - name, - optimization, - miss); + CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3, + holder, lookup, name, optimization, miss); } else { - CompileRegular(masm, - object, - receiver, - scratch1, - scratch2, - scratch3, - name, - holder, - miss); - return masm->isolate()->heap()->undefined_value(); // Success. + CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3, + name, holder, miss); } } private: - MaybeObject* CompileCacheable(MacroAssembler* masm, - JSObject* object, - Register receiver, - Register scratch1, - Register scratch2, - Register scratch3, - JSObject* interceptor_holder, - LookupResult* lookup, - String* name, - const CallOptimization& optimization, - Label* miss_label) { + void CompileCacheable(MacroAssembler* masm, + Handle<JSObject> object, + Register receiver, + Register scratch1, + Register scratch2, + Register scratch3, + Handle<JSObject> interceptor_holder, + LookupResult* lookup, + Handle<String> name, + const CallOptimization& optimization, + Label* miss_label) { ASSERT(optimization.is_constant_call()); ASSERT(!lookup->holder()->IsGlobalObject()); @@ -549,16 +526,14 @@ class CallInterceptorCompiler BASE_EMBEDDED { bool can_do_fast_api_call = false; if (optimization.is_simple_api_call() && !lookup->holder()->IsGlobalObject()) { - depth1 = - optimization.GetPrototypeDepthOfExpectedType(object, - interceptor_holder); + depth1 = optimization.GetPrototypeDepthOfExpectedType( + object, interceptor_holder); if (depth1 == kInvalidProtoDepth) { - depth2 = - optimization.GetPrototypeDepthOfExpectedType(interceptor_holder, - lookup->holder()); + depth2 = optimization.GetPrototypeDepthOfExpectedType( + interceptor_holder, Handle<JSObject>(lookup->holder())); } - can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || - (depth2 != kInvalidProtoDepth); + can_do_fast_api_call = + depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth; } Counters* counters = masm->isolate()->counters(); @@ -574,9 +549,9 @@ class CallInterceptorCompiler BASE_EMBEDDED { Label miss_cleanup; Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; Register holder = - stub_compiler_->CheckPrototypes(object, receiver, - interceptor_holder, scratch1, - scratch2, scratch3, name, depth1, miss); + stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, + scratch1, scratch2, scratch3, + name, depth1, miss); // Invoke an interceptor and if it provides a value, // branch to |regular_invoke|. @@ -589,10 +564,11 @@ class CallInterceptorCompiler BASE_EMBEDDED { // Check that the maps from interceptor's holder to constant function's // holder haven't changed and thus we can use cached constant function. - if (interceptor_holder != lookup->holder()) { + if (*interceptor_holder != lookup->holder()) { stub_compiler_->CheckPrototypes(interceptor_holder, receiver, - lookup->holder(), scratch1, - scratch2, scratch3, name, depth2, miss); + Handle<JSObject>(lookup->holder()), + scratch1, scratch2, scratch3, + name, depth2, miss); } else { // CheckPrototypes has a side effect of fetching a 'holder' // for API (object which is instanceof for the signature). It's @@ -603,10 +579,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { // Invoke function. if (can_do_fast_api_call) { - MaybeObject* result = GenerateFastApiCall(masm, - optimization, - arguments_.immediate()); - if (result->IsFailure()) return result; + GenerateFastApiCall(masm, optimization, arguments_.immediate()); } else { CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) ? CALL_AS_FUNCTION @@ -627,33 +600,27 @@ class CallInterceptorCompiler BASE_EMBEDDED { if (can_do_fast_api_call) { FreeSpaceForFastApiCall(masm, scratch1); } - - return masm->isolate()->heap()->undefined_value(); // Success. } void CompileRegular(MacroAssembler* masm, - JSObject* object, + Handle<JSObject> object, Register receiver, Register scratch1, Register scratch2, Register scratch3, - String* name, - JSObject* interceptor_holder, + Handle<String> name, + Handle<JSObject> interceptor_holder, Label* miss_label) { Register holder = stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, - scratch1, scratch2, scratch3, name, - miss_label); + scratch1, scratch2, scratch3, + name, miss_label); - __ EnterInternalFrame(); + FrameScope scope(masm, StackFrame::INTERNAL); // Save the name_ register across the call. __ push(name_); - PushInterceptorArguments(masm, - receiver, - holder, - name_, - interceptor_holder); + PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder); __ CallExternalReference( ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall), @@ -662,27 +629,30 @@ class CallInterceptorCompiler BASE_EMBEDDED { // Restore the name_ register. __ pop(name_); - __ LeaveInternalFrame(); + + // Leave the internal frame. } void LoadWithInterceptor(MacroAssembler* masm, Register receiver, Register holder, - JSObject* holder_obj, + Handle<JSObject> holder_obj, Label* interceptor_succeeded) { - __ EnterInternalFrame(); - __ push(holder); // Save the holder. - __ push(name_); // Save the name. - - CompileCallLoadPropertyWithInterceptor(masm, - receiver, - holder, - name_, - holder_obj); - - __ pop(name_); // Restore the name. - __ pop(receiver); // Restore the holder. - __ LeaveInternalFrame(); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ push(holder); // Save the holder. + __ push(name_); // Save the name. + + CompileCallLoadPropertyWithInterceptor(masm, + receiver, + holder, + name_, + holder_obj); + + __ pop(name_); // Restore the name. + __ pop(receiver); // Restore the holder. + // Leave the internal frame. + } __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); __ j(not_equal, interceptor_succeeded); @@ -697,32 +667,26 @@ class CallInterceptorCompiler BASE_EMBEDDED { void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); - Code* code = NULL; - if (kind == Code::LOAD_IC) { - code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss); - } else { - code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss); - } - - Handle<Code> ic(code); - __ Jump(ic, RelocInfo::CODE_TARGET); + Handle<Code> code = (kind == Code::LOAD_IC) + ? masm->isolate()->builtins()->LoadIC_Miss() + : masm->isolate()->builtins()->KeyedLoadIC_Miss(); + __ Jump(code, RelocInfo::CODE_TARGET); } void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) { - Code* code = masm->isolate()->builtins()->builtin( - Builtins::kKeyedLoadIC_MissForceGeneric); - Handle<Code> ic(code); - __ Jump(ic, RelocInfo::CODE_TARGET); + Handle<Code> code = + masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); + __ Jump(code, RelocInfo::CODE_TARGET); } // Both name_reg and receiver_reg are preserved on jumps to miss_label, // but may be destroyed if store is successful. void StubCompiler::GenerateStoreField(MacroAssembler* masm, - JSObject* object, + Handle<JSObject> object, int index, - Map* transition, + Handle<Map> transition, Register receiver_reg, Register name_reg, Register scratch, @@ -745,12 +709,12 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); // Perform map transition for the receiver if necessary. - if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) { + if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { // The properties must be extended before we can store the value. // We jump to a runtime call that extends the properties array. __ pop(scratch); // Return address. __ push(receiver_reg); - __ Push(Handle<Map>(transition)); + __ Push(transition); __ push(rax); __ push(scratch); __ TailCallExternalReference( @@ -761,11 +725,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, return; } - if (transition != NULL) { + if (!transition.is_null()) { // Update the map of the object; no write barrier updating is // needed because the map is never in new space. - __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset), - Handle<Map>(transition)); + __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset), transition); } // Adjust for the number of properties stored in the object. Even in the @@ -781,7 +744,8 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, // Update the write barrier for the array address. // Pass the value being stored in the now unused name_reg. __ movq(name_reg, rax); - __ RecordWrite(receiver_reg, offset, name_reg, scratch); + __ RecordWriteField( + receiver_reg, offset, name_reg, scratch, kDontSaveFPRegs); } else { // Write to the properties array. int offset = index * kPointerSize + FixedArray::kHeaderSize; @@ -792,7 +756,8 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, // Update the write barrier for the array address. // Pass the value being stored in the now unused name_reg. __ movq(name_reg, rax); - __ RecordWrite(scratch, offset, name_reg, receiver_reg); + __ RecordWriteField( + scratch, offset, name_reg, receiver_reg, kDontSaveFPRegs); } // Return the value (register rax). @@ -803,37 +768,53 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, // Generate code to check that a global property cell is empty. Create // the property cell at compilation time if no cell exists for the // property. -MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell( - MacroAssembler* masm, - GlobalObject* global, - String* name, - Register scratch, - Label* miss) { - Object* probe; - { MaybeObject* maybe_probe = global->EnsurePropertyCell(name); - if (!maybe_probe->ToObject(&probe)) return maybe_probe; - } - JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); +static void GenerateCheckPropertyCell(MacroAssembler* masm, + Handle<GlobalObject> global, + Handle<String> name, + Register scratch, + Label* miss) { + Handle<JSGlobalPropertyCell> cell = + GlobalObject::EnsurePropertyCell(global, name); ASSERT(cell->value()->IsTheHole()); - __ Move(scratch, Handle<Object>(cell)); + __ Move(scratch, cell); __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), masm->isolate()->factory()->the_hole_value()); __ j(not_equal, miss); - return cell; } +// Calls GenerateCheckPropertyCell for each global object in the prototype chain +// from object to (but not including) holder. +static void GenerateCheckPropertyCells(MacroAssembler* masm, + Handle<JSObject> object, + Handle<JSObject> holder, + Handle<String> name, + Register scratch, + Label* miss) { + Handle<JSObject> current = object; + while (!current.is_identical_to(holder)) { + if (current->IsGlobalObject()) { + GenerateCheckPropertyCell(masm, + Handle<GlobalObject>::cast(current), + name, + scratch, + miss); + } + current = Handle<JSObject>(JSObject::cast(current->GetPrototype())); + } +} + #undef __ #define __ ACCESS_MASM((masm())) -Register StubCompiler::CheckPrototypes(JSObject* object, +Register StubCompiler::CheckPrototypes(Handle<JSObject> object, Register object_reg, - JSObject* holder, + Handle<JSObject> holder, Register holder_reg, Register scratch1, Register scratch2, - String* name, + Handle<String> name, int save_at_depth, Label* miss) { // Make sure there's no overlap between holder and object registers. @@ -853,80 +834,58 @@ Register StubCompiler::CheckPrototypes(JSObject* object, // Check the maps in the prototype chain. // Traverse the prototype chain from the object and do map checks. - JSObject* current = object; - while (current != holder) { - depth++; + Handle<JSObject> current = object; + while (!current.is_identical_to(holder)) { + ++depth; // Only global objects and objects that do not require access // checks are allowed in stubs. ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); - JSObject* prototype = JSObject::cast(current->GetPrototype()); + Handle<JSObject> prototype(JSObject::cast(current->GetPrototype())); if (!current->HasFastProperties() && !current->IsJSGlobalObject() && !current->IsJSGlobalProxy()) { if (!name->IsSymbol()) { - MaybeObject* lookup_result = heap()->LookupSymbol(name); - if (lookup_result->IsFailure()) { - set_failure(Failure::cast(lookup_result)); - return reg; - } else { - name = String::cast(lookup_result->ToObjectUnchecked()); - } + name = factory()->LookupSymbol(name); } - ASSERT(current->property_dictionary()->FindEntry(name) == + ASSERT(current->property_dictionary()->FindEntry(*name) == StringDictionary::kNotFound); - MaybeObject* negative_lookup = GenerateDictionaryNegativeLookup(masm(), - miss, - reg, - name, - scratch1, - scratch2); - if (negative_lookup->IsFailure()) { - set_failure(Failure::cast(negative_lookup)); - return reg; - } + GenerateDictionaryNegativeLookup(masm(), miss, reg, name, + scratch1, scratch2); __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); - reg = holder_reg; // from now the object is in holder_reg + reg = holder_reg; // From now on the object will be in holder_reg. __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); - } else if (heap()->InNewSpace(prototype)) { - // Get the map of the current object. - __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); - __ Cmp(scratch1, Handle<Map>(current->map())); - // Branch on the result of the map check. - __ j(not_equal, miss); - // Check access rights to the global object. This has to happen - // after the map check so that we know that the object is - // actually a global object. - if (current->IsJSGlobalProxy()) { - __ CheckAccessGlobalProxy(reg, scratch1, miss); - - // Restore scratch register to be the map of the object. - // We load the prototype from the map in the scratch register. + } else { + bool in_new_space = heap()->InNewSpace(*prototype); + Handle<Map> current_map(current->map()); + if (in_new_space) { + // Save the map in scratch1 for later. __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); + __ Cmp(scratch1, current_map); + } else { + __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), current_map); } - // The prototype is in new space; we cannot store a reference - // to it in the code. Load it from the map. - reg = holder_reg; // from now the object is in holder_reg - __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); - - } else { - // Check the map of the current object. - __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), - Handle<Map>(current->map())); // Branch on the result of the map check. __ j(not_equal, miss); - // Check access rights to the global object. This has to happen - // after the map check so that we know that the object is - // actually a global object. + // Check access rights to the global object. This has to happen after + // the map check so that we know that the object is actually a global + // object. if (current->IsJSGlobalProxy()) { - __ CheckAccessGlobalProxy(reg, scratch1, miss); + __ CheckAccessGlobalProxy(reg, scratch2, miss); + } + reg = holder_reg; // From now on the object will be in holder_reg. + + if (in_new_space) { + // The prototype is in new space; we cannot store a reference to it + // in the code. Load it from the map. + __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); + } else { + // The prototype is in old space; load it directly. + __ Move(reg, prototype); } - // The prototype is in old space; load it directly. - reg = holder_reg; // from now the object is in holder_reg - __ Move(reg, Handle<JSObject>(prototype)); } if (save_at_depth == depth) { @@ -936,62 +895,46 @@ Register StubCompiler::CheckPrototypes(JSObject* object, // Go to the next object in the prototype chain. current = prototype; } + ASSERT(current.is_identical_to(holder)); + + // Log the check depth. + LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); // Check the holder map. __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), Handle<Map>(holder->map())); __ j(not_equal, miss); - // Log the check depth. - LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - - // Perform security check for access to the global object and return - // the holder register. - ASSERT(current == holder); + // Perform security check for access to the global object. ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); if (current->IsJSGlobalProxy()) { __ CheckAccessGlobalProxy(reg, scratch1, miss); } - // If we've skipped any global objects, it's not enough to verify - // that their maps haven't changed. We also need to check that the - // property cell for the property is still empty. - current = object; - while (current != holder) { - if (current->IsGlobalObject()) { - MaybeObject* cell = GenerateCheckPropertyCell(masm(), - GlobalObject::cast(current), - name, - scratch1, - miss); - if (cell->IsFailure()) { - set_failure(Failure::cast(cell)); - return reg; - } - } - current = JSObject::cast(current->GetPrototype()); - } + // If we've skipped any global objects, it's not enough to verify that + // their maps haven't changed. We also need to check that the property + // cell for the property is still empty. + GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss); // Return the register containing the holder. return reg; } -void StubCompiler::GenerateLoadField(JSObject* object, - JSObject* holder, +void StubCompiler::GenerateLoadField(Handle<JSObject> object, + Handle<JSObject> holder, Register receiver, Register scratch1, Register scratch2, Register scratch3, int index, - String* name, + Handle<String> name, Label* miss) { // Check that the receiver isn't a smi. __ JumpIfSmi(receiver, miss); // Check the prototype chain. - Register reg = - CheckPrototypes(object, receiver, holder, - scratch1, scratch2, scratch3, name, miss); + Register reg = CheckPrototypes( + object, receiver, holder, scratch1, scratch2, scratch3, name, miss); // Get the value from the properties. GenerateFastPropertyLoad(masm(), rax, reg, holder, index); @@ -999,25 +942,22 @@ void StubCompiler::GenerateLoadField(JSObject* object, } -MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, - JSObject* holder, - Register receiver, - Register name_reg, - Register scratch1, - Register scratch2, - Register scratch3, - AccessorInfo* callback, - String* name, - Label* miss) { +void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, + Handle<JSObject> holder, + Register receiver, + Register name_reg, + Register scratch1, + Register scratch2, + Register scratch3, + Handle<AccessorInfo> callback, + Handle<String> name, + Label* miss) { // Check that the receiver isn't a smi. __ JumpIfSmi(receiver, miss); // Check that the maps haven't changed. - Register reg = - CheckPrototypes(object, receiver, holder, scratch1, - scratch2, scratch3, name, miss); - - Handle<AccessorInfo> callback_handle(callback); + Register reg = CheckPrototypes(object, receiver, holder, scratch1, + scratch2, scratch3, name, miss); // Insert additional parameters into the stack frame above return address. ASSERT(!scratch2.is(reg)); @@ -1025,11 +965,11 @@ MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, __ push(receiver); // receiver __ push(reg); // holder - if (heap()->InNewSpace(callback_handle->data())) { - __ Move(scratch1, callback_handle); + if (heap()->InNewSpace(callback->data())) { + __ Move(scratch1, callback); __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); // data } else { - __ Push(Handle<Object>(callback_handle->data())); + __ Push(Handle<Object>(callback->data())); } __ push(name_reg); // name // Save a pointer to where we pushed the arguments pointer. @@ -1048,10 +988,6 @@ MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, __ movq(name_arg, rsp); __ push(scratch2); // Restore return address. - // Do call through the api. - Address getter_address = v8::ToCData<Address>(callback->getter()); - ApiFunction fun(getter_address); - // 3 elements array for v8::Agruments::values_ and handler for name. const int kStackSpace = 4; @@ -1068,45 +1004,42 @@ MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, // could be used to pass arguments. __ lea(accessor_info_arg, StackSpaceOperand(0)); - // Emitting a stub call may try to allocate (if the code is not - // already generated). Do not allow the assembler to perform a - // garbage collection but instead return the allocation failure - // object. - return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); + Address getter_address = v8::ToCData<Address>(callback->getter()); + __ CallApiFunctionAndReturn(getter_address, kStackSpace); } -void StubCompiler::GenerateLoadConstant(JSObject* object, - JSObject* holder, +void StubCompiler::GenerateLoadConstant(Handle<JSObject> object, + Handle<JSObject> holder, Register receiver, Register scratch1, Register scratch2, Register scratch3, - Object* value, - String* name, + Handle<Object> value, + Handle<String> name, Label* miss) { // Check that the receiver isn't a smi. __ JumpIfSmi(receiver, miss); // Check that the maps haven't changed. - CheckPrototypes(object, receiver, holder, - scratch1, scratch2, scratch3, name, miss); + CheckPrototypes( + object, receiver, holder, scratch1, scratch2, scratch3, name, miss); // Return the constant value. - __ Move(rax, Handle<Object>(value)); + __ Move(rax, value); __ ret(0); } -void StubCompiler::GenerateLoadInterceptor(JSObject* object, - JSObject* interceptor_holder, +void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, + Handle<JSObject> interceptor_holder, LookupResult* lookup, Register receiver, Register name_reg, Register scratch1, Register scratch2, Register scratch3, - String* name, + Handle<String> name, Label* miss) { ASSERT(interceptor_holder->HasNamedInterceptor()); ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); @@ -1122,9 +1055,9 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, if (lookup->type() == FIELD) { compile_followup_inline = true; } else if (lookup->type() == CALLBACKS && - lookup->GetCallbackObject()->IsAccessorInfo() && - AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) { - compile_followup_inline = true; + lookup->GetCallbackObject()->IsAccessorInfo()) { + compile_followup_inline = + AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL; } } @@ -1139,47 +1072,49 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, // Save necessary data before invoking an interceptor. // Requires a frame to make GC aware of pushed pointers. - __ EnterInternalFrame(); + { + FrameScope frame_scope(masm(), StackFrame::INTERNAL); - if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { - // CALLBACKS case needs a receiver to be passed into C++ callback. - __ push(receiver); - } - __ push(holder_reg); - __ push(name_reg); - - // Invoke an interceptor. Note: map checks from receiver to - // interceptor's holder has been compiled before (see a caller - // of this method.) - CompileCallLoadPropertyWithInterceptor(masm(), - receiver, - holder_reg, - name_reg, - interceptor_holder); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); - __ j(equal, &interceptor_failed); - __ LeaveInternalFrame(); - __ ret(0); + if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { + // CALLBACKS case needs a receiver to be passed into C++ callback. + __ push(receiver); + } + __ push(holder_reg); + __ push(name_reg); - __ bind(&interceptor_failed); - __ pop(name_reg); - __ pop(holder_reg); - if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { - __ pop(receiver); - } + // Invoke an interceptor. Note: map checks from receiver to + // interceptor's holder has been compiled before (see a caller + // of this method.) + CompileCallLoadPropertyWithInterceptor(masm(), + receiver, + holder_reg, + name_reg, + interceptor_holder); + + // Check if interceptor provided a value for property. If it's + // the case, return immediately. + Label interceptor_failed; + __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); + __ j(equal, &interceptor_failed); + frame_scope.GenerateLeaveFrame(); + __ ret(0); - __ LeaveInternalFrame(); + __ bind(&interceptor_failed); + __ pop(name_reg); + __ pop(holder_reg); + if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { + __ pop(receiver); + } + + // Leave the internal frame. + } // Check that the maps from interceptor's holder to lookup's holder // haven't changed. And load lookup's holder into |holder| register. - if (interceptor_holder != lookup->holder()) { + if (*interceptor_holder != lookup->holder()) { holder_reg = CheckPrototypes(interceptor_holder, holder_reg, - lookup->holder(), + Handle<JSObject>(lookup->holder()), scratch1, scratch2, scratch3, @@ -1191,15 +1126,15 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, // We found FIELD property in prototype chain of interceptor's holder. // Retrieve a field from field's holder. GenerateFastPropertyLoad(masm(), rax, holder_reg, - lookup->holder(), lookup->GetFieldIndex()); + Handle<JSObject>(lookup->holder()), + lookup->GetFieldIndex()); __ ret(0); } else { // We found CALLBACKS property in prototype chain of interceptor's // holder. ASSERT(lookup->type() == CALLBACKS); - ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); - AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); - ASSERT(callback != NULL); + Handle<AccessorInfo> callback( + AccessorInfo::cast(lookup->GetCallbackObject())); ASSERT(callback->getter() != NULL); // Tail call to runtime. @@ -1208,7 +1143,7 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, __ pop(scratch2); // return address __ push(receiver); __ push(holder_reg); - __ Move(holder_reg, Handle<AccessorInfo>(callback)); + __ Move(holder_reg, callback); __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset)); __ push(holder_reg); __ push(name_reg); @@ -1237,17 +1172,17 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, } -void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) { +void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) { if (kind_ == Code::KEYED_CALL_IC) { - __ Cmp(rcx, Handle<String>(name)); + __ Cmp(rcx, name); __ j(not_equal, miss); } } -void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object, - JSObject* holder, - String* name, +void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object, + Handle<JSObject> holder, + Handle<String> name, Label* miss) { ASSERT(holder->IsGlobalObject()); @@ -1260,7 +1195,7 @@ void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object, // If the object is the holder then we know that it's a global // object which can only happen for contextual calls. In this case, // the receiver cannot be a smi. - if (object != holder) { + if (!object.is_identical_to(holder)) { __ JumpIfSmi(rdx, miss); } @@ -1269,15 +1204,16 @@ void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object, } -void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, - JSFunction* function, - Label* miss) { +void CallStubCompiler::GenerateLoadFunctionFromCell( + Handle<JSGlobalPropertyCell> cell, + Handle<JSFunction> function, + Label* miss) { // Get the value from the cell. - __ Move(rdi, Handle<JSGlobalPropertyCell>(cell)); + __ Move(rdi, cell); __ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset)); // Check that the cell contains the same function. - if (heap()->InNewSpace(function)) { + if (heap()->InNewSpace(*function)) { // We can't embed a pointer to a function in new space so we have // to verify that the shared function info is unchanged. This has // the nice side effect that multiple closures based on the same @@ -1290,30 +1226,26 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, // Check the shared function info. Make sure it hasn't changed. __ Move(rax, Handle<SharedFunctionInfo>(function->shared())); __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax); - __ j(not_equal, miss); } else { - __ Cmp(rdi, Handle<JSFunction>(function)); - __ j(not_equal, miss); + __ Cmp(rdi, function); } + __ j(not_equal, miss); } -MaybeObject* CallStubCompiler::GenerateMissBranch() { - MaybeObject* maybe_obj = +void CallStubCompiler::GenerateMissBranch() { + Handle<Code> code = isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), kind_, - extra_ic_state_); - Object* obj; - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); - return obj; + extra_state_); + __ Jump(code, RelocInfo::CODE_TARGET); } -MaybeObject* CallStubCompiler::CompileCallField(JSObject* object, - JSObject* holder, +Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, + Handle<JSObject> holder, int index, - String* name) { + Handle<String> name) { // ----------- S t a t e ------------- // rcx : function name // rsp[0] : return address @@ -1353,7 +1285,7 @@ MaybeObject* CallStubCompiler::CompileCallField(JSObject* object, } // Invoke the function. - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION, @@ -1361,19 +1293,19 @@ MaybeObject* CallStubCompiler::CompileCallField(JSObject* object, // Handle call cache miss. __ bind(&miss); - MaybeObject* maybe_result = GenerateMissBranch(); - if (maybe_result->IsFailure()) return maybe_result; + GenerateMissBranch(); // Return the generated code. return GetCode(FIELD, name); } -MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, - JSObject* holder, - JSGlobalPropertyCell* cell, - JSFunction* function, - String* name) { +Handle<Code> CallStubCompiler::CompileArrayPushCall( + Handle<Object> object, + Handle<JSObject> holder, + Handle<JSGlobalPropertyCell> cell, + Handle<JSFunction> function, + Handle<String> name) { // ----------- S t a t e ------------- // -- rcx : name // -- rsp[0] : return address @@ -1383,10 +1315,9 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, // ----------------------------------- // If object is not an array, bail out to regular call. - if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value(); + if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null(); Label miss; - GenerateNameCheck(name, &miss); // Get the receiver from the stack. @@ -1396,14 +1327,8 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, // Check that the receiver isn't a smi. __ JumpIfSmi(rdx, &miss); - CheckPrototypes(JSObject::cast(object), - rdx, - holder, - rbx, - rax, - rdi, - name, - &miss); + CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi, + name, &miss); if (argc == 0) { // Noop, return the length. @@ -1421,7 +1346,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, __ j(not_equal, &call_builtin); if (argc == 1) { // Otherwise fall through to call builtin. - Label exit, with_write_barrier, attempt_to_grow_elements; + Label attempt_to_grow_elements, with_write_barrier; // Get the array's length into rax and calculate new length. __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset)); @@ -1435,30 +1360,40 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, __ cmpl(rax, rcx); __ j(greater, &attempt_to_grow_elements); + // Check if value is a smi. + __ movq(rcx, Operand(rsp, argc * kPointerSize)); + __ JumpIfNotSmi(rcx, &with_write_barrier); + // Save new length. __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax); // Push the element. - __ movq(rcx, Operand(rsp, argc * kPointerSize)); __ lea(rdx, FieldOperand(rbx, rax, times_pointer_size, FixedArray::kHeaderSize - argc * kPointerSize)); __ movq(Operand(rdx, 0), rcx); - // Check if value is a smi. __ Integer32ToSmi(rax, rax); // Return new length as smi. - - __ JumpIfNotSmi(rcx, &with_write_barrier); - - __ bind(&exit); __ ret((argc + 1) * kPointerSize); __ bind(&with_write_barrier); - __ InNewSpace(rbx, rcx, equal, &exit); + __ movq(rdi, FieldOperand(rdx, HeapObject::kMapOffset)); + __ CheckFastObjectElements(rdi, &call_builtin); + + // Save new length. + __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax); + + // Push the element. + __ lea(rdx, FieldOperand(rbx, + rax, times_pointer_size, + FixedArray::kHeaderSize - argc * kPointerSize)); + __ movq(Operand(rdx, 0), rcx); - __ RecordWriteHelper(rbx, rdx, rcx); + __ RecordWrite(rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + __ Integer32ToSmi(rax, rax); // Return new length as smi. __ ret((argc + 1) * kPointerSize); __ bind(&attempt_to_grow_elements); @@ -1466,6 +1401,15 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, __ jmp(&call_builtin); } + __ movq(rdi, Operand(rsp, argc * kPointerSize)); + // Growing elements that are SMI-only requires special handling in case + // the new element is non-Smi. For now, delegate to the builtin. + Label no_fast_elements_check; + __ JumpIfSmi(rdi, &no_fast_elements_check); + __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset)); + __ CheckFastObjectElements(rcx, &call_builtin, Label::kFar); + __ bind(&no_fast_elements_check); + ExternalReference new_space_allocation_top = ExternalReference::new_space_allocation_top_address(isolate()); ExternalReference new_space_allocation_limit = @@ -1489,16 +1433,22 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, // We fit and could grow elements. __ Store(new_space_allocation_top, rcx); - __ movq(rcx, Operand(rsp, argc * kPointerSize)); // Push the argument... - __ movq(Operand(rdx, 0), rcx); + __ movq(Operand(rdx, 0), rdi); // ... and fill the rest with holes. __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); for (int i = 1; i < kAllocationDelta; i++) { __ movq(Operand(rdx, i * kPointerSize), kScratchRegister); } + // We know the elements array is in new space so we don't need the + // remembered set, but we just pushed a value onto it so we may have to + // tell the incremental marker to rescan the object that we just grew. We + // don't need to worry about the holes because they are in old space and + // already marked black. + __ RecordWrite(rbx, rdx, rdi, kDontSaveFPRegs, OMIT_REMEMBERED_SET); + // Restore receiver to rdx as finish sequence assumes it's here. __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); @@ -1510,7 +1460,6 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, __ Integer32ToSmi(rax, rax); __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax); - // Elements are in new space, so write barrier is not required. __ ret((argc + 1) * kPointerSize); } @@ -1522,19 +1471,19 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, } __ bind(&miss); - MaybeObject* maybe_result = GenerateMissBranch(); - if (maybe_result->IsFailure()) return maybe_result; + GenerateMissBranch(); // Return the generated code. return GetCode(function); } -MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object, - JSObject* holder, - JSGlobalPropertyCell* cell, - JSFunction* function, - String* name) { +Handle<Code> CallStubCompiler::CompileArrayPopCall( + Handle<Object> object, + Handle<JSObject> holder, + Handle<JSGlobalPropertyCell> cell, + Handle<JSFunction> function, + Handle<String> name) { // ----------- S t a t e ------------- // -- rcx : name // -- rsp[0] : return address @@ -1544,10 +1493,9 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object, // ----------------------------------- // If object is not an array, bail out to regular call. - if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value(); + if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null(); Label miss, return_undefined, call_builtin; - GenerateNameCheck(name, &miss); // Get the receiver from the stack. @@ -1557,9 +1505,8 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object, // Check that the receiver isn't a smi. __ JumpIfSmi(rdx, &miss); - CheckPrototypes(JSObject::cast(object), rdx, - holder, rbx, - rax, rdi, name, &miss); + CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi, + name, &miss); // Get the elements array of the object. __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset)); @@ -1605,20 +1552,19 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object, 1); __ bind(&miss); - MaybeObject* maybe_result = GenerateMissBranch(); - if (maybe_result->IsFailure()) return maybe_result; + GenerateMissBranch(); // Return the generated code. return GetCode(function); } -MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( - Object* object, - JSObject* holder, - JSGlobalPropertyCell* cell, - JSFunction* function, - String* name) { +Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall( + Handle<Object> object, + Handle<JSObject> holder, + Handle<JSGlobalPropertyCell> cell, + Handle<JSFunction> function, + Handle<String> name) { // ----------- S t a t e ------------- // -- rcx : function name // -- rsp[0] : return address @@ -1628,7 +1574,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( // ----------------------------------- // If object is not a string, bail out to regular call. - if (!object->IsString() || cell != NULL) return heap()->undefined_value(); + if (!object->IsString() || !cell.is_null()) return Handle<Code>::null(); const int argc = arguments().immediate(); @@ -1636,13 +1582,11 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( Label name_miss; Label index_out_of_range; Label* index_out_of_range_label = &index_out_of_range; - if (kind_ == Code::CALL_IC && - (CallICBase::StringStubState::decode(extra_ic_state_) == + (CallICBase::StringStubState::decode(extra_state_) == DEFAULT_STRING_STUB)) { index_out_of_range_label = &miss; } - GenerateNameCheck(name, &name_miss); // Check that the maps starting from the prototype haven't changed. @@ -1650,13 +1594,12 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( Context::STRING_FUNCTION_INDEX, rax, &miss); - ASSERT(object != holder); - CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, - rbx, rdx, rdi, name, &miss); + ASSERT(!object.is_identical_to(holder)); + CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())), + rax, holder, rbx, rdx, rdi, name, &miss); Register receiver = rbx; Register index = rdi; - Register scratch = rdx; Register result = rax; __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); if (argc > 0) { @@ -1665,19 +1608,18 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( __ LoadRoot(index, Heap::kUndefinedValueRootIndex); } - StringCharCodeAtGenerator char_code_at_generator(receiver, - index, - scratch, - result, - &miss, // When not a string. - &miss, // When not a number. - index_out_of_range_label, - STRING_INDEX_IS_NUMBER); - char_code_at_generator.GenerateFast(masm()); + StringCharCodeAtGenerator generator(receiver, + index, + result, + &miss, // When not a string. + &miss, // When not a number. + index_out_of_range_label, + STRING_INDEX_IS_NUMBER); + generator.GenerateFast(masm()); __ ret((argc + 1) * kPointerSize); StubRuntimeCallHelper call_helper; - char_code_at_generator.GenerateSlow(masm(), call_helper); + generator.GenerateSlow(masm(), call_helper); if (index_out_of_range.is_linked()) { __ bind(&index_out_of_range); @@ -1687,22 +1629,21 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( __ bind(&miss); // Restore function name in rcx. - __ Move(rcx, Handle<String>(name)); + __ Move(rcx, name); __ bind(&name_miss); - MaybeObject* maybe_result = GenerateMissBranch(); - if (maybe_result->IsFailure()) return maybe_result; + GenerateMissBranch(); // Return the generated code. return GetCode(function); } -MaybeObject* CallStubCompiler::CompileStringCharAtCall( - Object* object, - JSObject* holder, - JSGlobalPropertyCell* cell, - JSFunction* function, - String* name) { +Handle<Code> CallStubCompiler::CompileStringCharAtCall( + Handle<Object> object, + Handle<JSObject> holder, + Handle<JSGlobalPropertyCell> cell, + Handle<JSFunction> function, + Handle<String> name) { // ----------- S t a t e ------------- // -- rcx : function name // -- rsp[0] : return address @@ -1712,21 +1653,18 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( // ----------------------------------- // If object is not a string, bail out to regular call. - if (!object->IsString() || cell != NULL) return heap()->undefined_value(); + if (!object->IsString() || !cell.is_null()) return Handle<Code>::null(); const int argc = arguments().immediate(); - Label miss; Label name_miss; Label index_out_of_range; Label* index_out_of_range_label = &index_out_of_range; - if (kind_ == Code::CALL_IC && - (CallICBase::StringStubState::decode(extra_ic_state_) == + (CallICBase::StringStubState::decode(extra_state_) == DEFAULT_STRING_STUB)) { index_out_of_range_label = &miss; } - GenerateNameCheck(name, &name_miss); // Check that the maps starting from the prototype haven't changed. @@ -1734,14 +1672,13 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( Context::STRING_FUNCTION_INDEX, rax, &miss); - ASSERT(object != holder); - CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, - rbx, rdx, rdi, name, &miss); + ASSERT(!object.is_identical_to(holder)); + CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())), + rax, holder, rbx, rdx, rdi, name, &miss); Register receiver = rax; Register index = rdi; - Register scratch1 = rbx; - Register scratch2 = rdx; + Register scratch = rdx; Register result = rax; __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); if (argc > 0) { @@ -1750,45 +1687,42 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( __ LoadRoot(index, Heap::kUndefinedValueRootIndex); } - StringCharAtGenerator char_at_generator(receiver, - index, - scratch1, - scratch2, - result, - &miss, // When not a string. - &miss, // When not a number. - index_out_of_range_label, - STRING_INDEX_IS_NUMBER); - char_at_generator.GenerateFast(masm()); + StringCharAtGenerator generator(receiver, + index, + scratch, + result, + &miss, // When not a string. + &miss, // When not a number. + index_out_of_range_label, + STRING_INDEX_IS_NUMBER); + generator.GenerateFast(masm()); __ ret((argc + 1) * kPointerSize); StubRuntimeCallHelper call_helper; - char_at_generator.GenerateSlow(masm(), call_helper); + generator.GenerateSlow(masm(), call_helper); if (index_out_of_range.is_linked()) { __ bind(&index_out_of_range); __ LoadRoot(rax, Heap::kEmptyStringRootIndex); __ ret((argc + 1) * kPointerSize); } - __ bind(&miss); // Restore function name in rcx. - __ Move(rcx, Handle<String>(name)); + __ Move(rcx, name); __ bind(&name_miss); - MaybeObject* maybe_result = GenerateMissBranch(); - if (maybe_result->IsFailure()) return maybe_result; + GenerateMissBranch(); // Return the generated code. return GetCode(function); } -MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall( - Object* object, - JSObject* holder, - JSGlobalPropertyCell* cell, - JSFunction* function, - String* name) { +Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall( + Handle<Object> object, + Handle<JSObject> holder, + Handle<JSGlobalPropertyCell> cell, + Handle<JSFunction> function, + Handle<String> name) { // ----------- S t a t e ------------- // -- rcx : function name // -- rsp[0] : return address @@ -1797,25 +1731,23 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall( // -- rsp[(argc + 1) * 8] : receiver // ----------------------------------- - const int argc = arguments().immediate(); - // If the object is not a JSObject or we got an unexpected number of // arguments, bail out to the regular call. - if (!object->IsJSObject() || argc != 1) return heap()->undefined_value(); + const int argc = arguments().immediate(); + if (!object->IsJSObject() || argc != 1) return Handle<Code>::null(); Label miss; GenerateNameCheck(name, &miss); - if (cell == NULL) { + if (cell.is_null()) { __ movq(rdx, Operand(rsp, 2 * kPointerSize)); - __ JumpIfSmi(rdx, &miss); - - CheckPrototypes(JSObject::cast(object), rdx, holder, rbx, rax, rdi, name, - &miss); + CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi, + name, &miss); } else { - ASSERT(cell->value() == function); - GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); + ASSERT(cell->value() == *function); + GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, + &miss); GenerateLoadFunctionFromCell(cell, function, &miss); } @@ -1830,17 +1762,17 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall( // Convert the smi code to uint16. __ SmiAndConstant(code, code, Smi::FromInt(0xffff)); - StringCharFromCodeGenerator char_from_code_generator(code, rax); - char_from_code_generator.GenerateFast(masm()); + StringCharFromCodeGenerator generator(code, rax); + generator.GenerateFast(masm()); __ ret(2 * kPointerSize); StubRuntimeCallHelper call_helper; - char_from_code_generator.GenerateSlow(masm(), call_helper); + generator.GenerateSlow(masm(), call_helper); // Tail call the full function. We do not have to patch the receiver // because the function makes no use of it. __ bind(&slow); - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(function, arguments(), JUMP_FUNCTION, @@ -1848,29 +1780,30 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall( __ bind(&miss); // rcx: function name. - MaybeObject* maybe_result = GenerateMissBranch(); - if (maybe_result->IsFailure()) return maybe_result; + GenerateMissBranch(); // Return the generated code. - return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); + return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name); } -MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object, - JSObject* holder, - JSGlobalPropertyCell* cell, - JSFunction* function, - String* name) { +Handle<Code> CallStubCompiler::CompileMathFloorCall( + Handle<Object> object, + Handle<JSObject> holder, + Handle<JSGlobalPropertyCell> cell, + Handle<JSFunction> function, + Handle<String> name) { // TODO(872): implement this. - return heap()->undefined_value(); + return Handle<Code>::null(); } -MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object, - JSObject* holder, - JSGlobalPropertyCell* cell, - JSFunction* function, - String* name) { +Handle<Code> CallStubCompiler::CompileMathAbsCall( + Handle<Object> object, + Handle<JSObject> holder, + Handle<JSGlobalPropertyCell> cell, + Handle<JSFunction> function, + Handle<String> name) { // ----------- S t a t e ------------- // -- rcx : function name // -- rsp[0] : return address @@ -1879,28 +1812,25 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object, // -- rsp[(argc + 1) * 8] : receiver // ----------------------------------- - const int argc = arguments().immediate(); - // If the object is not a JSObject or we got an unexpected number of // arguments, bail out to the regular call. - if (!object->IsJSObject() || argc != 1) return heap()->undefined_value(); + const int argc = arguments().immediate(); + if (!object->IsJSObject() || argc != 1) return Handle<Code>::null(); Label miss; GenerateNameCheck(name, &miss); - if (cell == NULL) { + if (cell.is_null()) { __ movq(rdx, Operand(rsp, 2 * kPointerSize)); - __ JumpIfSmi(rdx, &miss); - - CheckPrototypes(JSObject::cast(object), rdx, holder, rbx, rax, rdi, name, - &miss); + CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi, + name, &miss); } else { - ASSERT(cell->value() == function); - GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); + ASSERT(cell->value() == *function); + GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, + &miss); GenerateLoadFunctionFromCell(cell, function, &miss); } - // Load the (only) argument into rax. __ movq(rax, Operand(rsp, 1 * kPointerSize)); @@ -1957,7 +1887,7 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object, // Tail call the full function. We do not have to patch the receiver // because the function makes no use of it. __ bind(&slow); - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(function, arguments(), JUMP_FUNCTION, @@ -1965,33 +1895,31 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object, __ bind(&miss); // rcx: function name. - MaybeObject* maybe_result = GenerateMissBranch(); - if (maybe_result->IsFailure()) return maybe_result; + GenerateMissBranch(); // Return the generated code. - return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); + return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name); } -MaybeObject* CallStubCompiler::CompileFastApiCall( +Handle<Code> CallStubCompiler::CompileFastApiCall( const CallOptimization& optimization, - Object* object, - JSObject* holder, - JSGlobalPropertyCell* cell, - JSFunction* function, - String* name) { + Handle<Object> object, + Handle<JSObject> holder, + Handle<JSGlobalPropertyCell> cell, + Handle<JSFunction> function, + Handle<String> name) { ASSERT(optimization.is_simple_api_call()); // Bail out if object is a global object as we don't want to // repatch it to global receiver. - if (object->IsGlobalObject()) return heap()->undefined_value(); - if (cell != NULL) return heap()->undefined_value(); - if (!object->IsJSObject()) return heap()->undefined_value(); + if (object->IsGlobalObject()) return Handle<Code>::null(); + if (!cell.is_null()) return Handle<Code>::null(); + if (!object->IsJSObject()) return Handle<Code>::null(); int depth = optimization.GetPrototypeDepthOfExpectedType( - JSObject::cast(object), holder); - if (depth == kInvalidProtoDepth) return heap()->undefined_value(); + Handle<JSObject>::cast(object), holder); + if (depth == kInvalidProtoDepth) return Handle<Code>::null(); Label miss, miss_before_stack_reserved; - GenerateNameCheck(name, &miss_before_stack_reserved); // Get the receiver from the stack. @@ -2010,32 +1938,30 @@ MaybeObject* CallStubCompiler::CompileFastApiCall( __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize)); // Check that the maps haven't changed and find a Holder as a side effect. - CheckPrototypes(JSObject::cast(object), rdx, holder, - rbx, rax, rdi, name, depth, &miss); + CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi, + name, depth, &miss); // Move the return address on top of the stack. __ movq(rax, Operand(rsp, 3 * kPointerSize)); __ movq(Operand(rsp, 0 * kPointerSize), rax); - MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc); - if (result->IsFailure()) return result; + GenerateFastApiCall(masm(), optimization, argc); __ bind(&miss); __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize)); __ bind(&miss_before_stack_reserved); - MaybeObject* maybe_result = GenerateMissBranch(); - if (maybe_result->IsFailure()) return maybe_result; + GenerateMissBranch(); // Return the generated code. return GetCode(function); } -MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, - JSObject* holder, - JSFunction* function, - String* name, +Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object, + Handle<JSObject> holder, + Handle<JSFunction> function, + Handle<String> name, CheckType check) { // ----------- S t a t e ------------- // rcx : function name @@ -2048,16 +1974,14 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, // ----------------------------------- if (HasCustomCallGenerator(function)) { - MaybeObject* maybe_result = CompileCustomCall( - object, holder, NULL, function, name); - Object* result; - if (!maybe_result->ToObject(&result)) return maybe_result; - // undefined means bail out to regular compiler. - if (!result->IsUndefined()) return result; + Handle<Code> code = CompileCustomCall(object, holder, + Handle<JSGlobalPropertyCell>::null(), + function, name); + // A null handle means bail out to the regular compiler code below. + if (!code.is_null()) return code; } Label miss; - GenerateNameCheck(name, &miss); // Get the receiver from the stack. @@ -2074,14 +1998,13 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); Counters* counters = isolate()->counters(); - SharedFunctionInfo* function_info = function->shared(); switch (check) { case RECEIVER_MAP_CHECK: __ IncrementCounter(counters->call_const(), 1); // Check that the maps haven't changed. - CheckPrototypes(JSObject::cast(object), rdx, holder, - rbx, rax, rdi, name, &miss); + CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, + rdi, name, &miss); // Patch the receiver on the stack with the global proxy if // necessary. @@ -2092,28 +2015,25 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, break; case STRING_CHECK: - if (!function->IsBuiltin() && !function_info->strict_mode()) { - // Calling non-strict non-builtins with a value as the receiver - // requires boxing. - __ jmp(&miss); - } else { + if (function->IsBuiltin() || !function->shared()->is_classic_mode()) { // Check that the object is a two-byte string or a symbol. __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax); __ j(above_equal, &miss); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( masm(), Context::STRING_FUNCTION_INDEX, rax, &miss); - CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, - rbx, rdx, rdi, name, &miss); - } - break; - - case NUMBER_CHECK: { - if (!function->IsBuiltin() && !function_info->strict_mode()) { + CheckPrototypes( + Handle<JSObject>(JSObject::cast(object->GetPrototype())), + rax, holder, rbx, rdx, rdi, name, &miss); + } else { // Calling non-strict non-builtins with a value as the receiver // requires boxing. __ jmp(&miss); - } else { + } + break; + + case NUMBER_CHECK: + if (function->IsBuiltin() || !function->shared()->is_classic_mode()) { Label fast; // Check that the object is a smi or a heap number. __ JumpIfSmi(rdx, &fast); @@ -2123,18 +2043,18 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss); - CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, - rbx, rdx, rdi, name, &miss); - } - break; - } - - case BOOLEAN_CHECK: { - if (!function->IsBuiltin() && !function_info->strict_mode()) { + CheckPrototypes( + Handle<JSObject>(JSObject::cast(object->GetPrototype())), + rax, holder, rbx, rdx, rdi, name, &miss); + } else { // Calling non-strict non-builtins with a value as the receiver // requires boxing. __ jmp(&miss); - } else { + } + break; + + case BOOLEAN_CHECK: + if (function->IsBuiltin() || !function->shared()->is_classic_mode()) { Label fast; // Check that the object is a boolean. __ CompareRoot(rdx, Heap::kTrueValueRootIndex); @@ -2145,17 +2065,18 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss); - CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, - rbx, rdx, rdi, name, &miss); + CheckPrototypes( + Handle<JSObject>(JSObject::cast(object->GetPrototype())), + rax, holder, rbx, rdx, rdi, name, &miss); + } else { + // Calling non-strict non-builtins with a value as the receiver + // requires boxing. + __ jmp(&miss); } break; - } - - default: - UNREACHABLE(); } - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(function, arguments(), JUMP_FUNCTION, @@ -2163,17 +2084,16 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, // Handle call cache miss. __ bind(&miss); - MaybeObject* maybe_result = GenerateMissBranch(); - if (maybe_result->IsFailure()) return maybe_result; + GenerateMissBranch(); // Return the generated code. return GetCode(function); } -MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, - JSObject* holder, - String* name) { +Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object, + Handle<JSObject> holder, + Handle<String> name) { // ----------- S t a t e ------------- // rcx : function name // rsp[0] : return address @@ -2184,30 +2104,20 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, // rsp[(argc + 1) * 8] : argument 0 = receiver // ----------------------------------- Label miss; - GenerateNameCheck(name, &miss); // Get the number of arguments. const int argc = arguments().immediate(); - LookupResult lookup; + LookupResult lookup(isolate()); LookupPostInterceptor(holder, name, &lookup); // Get the receiver from the stack. __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); - CallInterceptorCompiler compiler(this, arguments(), rcx, extra_ic_state_); - MaybeObject* result = compiler.Compile(masm(), - object, - holder, - name, - &lookup, - rdx, - rbx, - rdi, - rax, - &miss); - if (result->IsFailure()) return result; + CallInterceptorCompiler compiler(this, arguments(), rcx, extra_state_); + compiler.Compile(masm(), object, holder, name, &lookup, rdx, rbx, rdi, rax, + &miss); // Restore receiver. __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); @@ -2226,7 +2136,7 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, // Invoke the function. __ movq(rdi, rax); - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION, @@ -2234,19 +2144,19 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, // Handle load cache miss. __ bind(&miss); - MaybeObject* maybe_result = GenerateMissBranch(); - if (maybe_result->IsFailure()) return maybe_result; + GenerateMissBranch(); // Return the generated code. return GetCode(INTERCEPTOR, name); } -MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object, - GlobalObject* holder, - JSGlobalPropertyCell* cell, - JSFunction* function, - String* name) { +Handle<Code> CallStubCompiler::CompileCallGlobal( + Handle<JSObject> object, + Handle<GlobalObject> holder, + Handle<JSGlobalPropertyCell> cell, + Handle<JSFunction> function, + Handle<String> name) { // ----------- S t a t e ------------- // rcx : function name // rsp[0] : return address @@ -2258,23 +2168,17 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object, // ----------------------------------- if (HasCustomCallGenerator(function)) { - MaybeObject* maybe_result = CompileCustomCall( - object, holder, cell, function, name); - Object* result; - if (!maybe_result->ToObject(&result)) return maybe_result; - // undefined means bail out to regular compiler. - if (!result->IsUndefined()) return result; + Handle<Code> code = CompileCustomCall(object, holder, cell, function, name); + // A null handle means bail out to the regular compiler code below. + if (!code.is_null()) return code; } Label miss; - GenerateNameCheck(name, &miss); // Get the number of arguments. const int argc = arguments().immediate(); - GenerateGlobalReceiverCheck(object, holder, name, &miss); - GenerateLoadFunctionFromCell(cell, function, &miss); // Patch the receiver on the stack with the global proxy. @@ -2289,39 +2193,31 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object, // Jump to the cached code (tail call). Counters* counters = isolate()->counters(); __ IncrementCounter(counters->call_global_inline(), 1); - ASSERT(function->is_compiled()); ParameterCount expected(function->shared()->formal_parameter_count()); - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; - if (V8::UseCrankshaft()) { - // TODO(kasperl): For now, we always call indirectly through the - // code field in the function to allow recompilation to take effect - // without changing any of the call sites. - __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); - __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION, - NullCallWrapper(), call_kind); - } else { - Handle<Code> code(function->code()); - __ InvokeCode(code, expected, arguments(), - RelocInfo::CODE_TARGET, JUMP_FUNCTION, - NullCallWrapper(), call_kind); - } + // We call indirectly through the code field in the function to + // allow recompilation to take effect without changing any of the + // call sites. + __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); + __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION, + NullCallWrapper(), call_kind); + // Handle call cache miss. __ bind(&miss); __ IncrementCounter(counters->call_global_inline_miss(), 1); - MaybeObject* maybe_result = GenerateMissBranch(); - if (maybe_result->IsFailure()) return maybe_result; + GenerateMissBranch(); // Return the generated code. return GetCode(NORMAL, name); } -MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object, +Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object, int index, - Map* transition, - String* name) { + Handle<Map> transition, + Handle<String> name) { // ----------- S t a t e ------------- // -- rax : value // -- rcx : name @@ -2331,12 +2227,7 @@ MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object, Label miss; // Generate store field code. Preserves receiver and name on jump to miss. - GenerateStoreField(masm(), - object, - index, - transition, - rdx, rcx, rbx, - &miss); + GenerateStoreField(masm(), object, index, transition, rdx, rcx, rbx, &miss); // Handle store cache miss. __ bind(&miss); @@ -2344,13 +2235,14 @@ MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object, __ Jump(ic, RelocInfo::CODE_TARGET); // Return the generated code. - return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); + return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); } -MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object, - AccessorInfo* callback, - String* name) { +Handle<Code> StoreStubCompiler::CompileStoreCallback( + Handle<JSObject> object, + Handle<AccessorInfo> callback, + Handle<String> name) { // ----------- S t a t e ------------- // -- rax : value // -- rcx : name @@ -2378,7 +2270,7 @@ MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object, __ pop(rbx); // remove the return address __ push(rdx); // receiver - __ Push(Handle<AccessorInfo>(callback)); // callback info + __ Push(callback); // callback info __ push(rcx); // name __ push(rax); // value __ push(rbx); // restore return address @@ -2398,8 +2290,9 @@ MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object, } -MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, - String* name) { +Handle<Code> StoreStubCompiler::CompileStoreInterceptor( + Handle<JSObject> receiver, + Handle<String> name) { // ----------- S t a t e ------------- // -- rax : value // -- rcx : name @@ -2447,9 +2340,10 @@ MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, } -MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, - JSGlobalPropertyCell* cell, - String* name) { +Handle<Code> StoreStubCompiler::CompileStoreGlobal( + Handle<GlobalObject> object, + Handle<JSGlobalPropertyCell> cell, + Handle<String> name) { // ----------- S t a t e ------------- // -- rax : value // -- rcx : name @@ -2463,19 +2357,36 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, Handle<Map>(object->map())); __ j(not_equal, &miss); + // Compute the cell operand to use. + __ Move(rbx, cell); + Operand cell_operand = FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset); + // Check that the value in the cell is not the hole. If it is, this // cell could have been deleted and reintroducing the global needs // to update the property details in the property dictionary of the // global object. We bail out to the runtime system to do that. - __ Move(rbx, Handle<JSGlobalPropertyCell>(cell)); - __ CompareRoot(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), - Heap::kTheHoleValueRootIndex); + __ CompareRoot(cell_operand, Heap::kTheHoleValueRootIndex); __ j(equal, &miss); // Store the value in the cell. - __ movq(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), rax); + __ movq(cell_operand, rax); + Label done; + __ JumpIfSmi(rax, &done); + + __ movq(rcx, rax); + __ lea(rdx, cell_operand); + // Cells are always in the remembered set. + __ RecordWrite(rbx, // Object. + rdx, // Address. + rcx, // Value. + kDontSaveFPRegs, + OMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + // Return the value (register rax). + __ bind(&done); + Counters* counters = isolate()->counters(); __ IncrementCounter(counters->named_store_global_inline(), 1); __ ret(0); @@ -2491,10 +2402,10 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, } -MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, +Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object, int index, - Map* transition, - String* name) { + Handle<Map> transition, + Handle<String> name) { // ----------- S t a t e ------------- // -- rax : value // -- rcx : key @@ -2507,16 +2418,11 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, __ IncrementCounter(counters->keyed_store_field(), 1); // Check that the name has not changed. - __ Cmp(rcx, Handle<String>(name)); + __ Cmp(rcx, name); __ j(not_equal, &miss); // Generate store field code. Preserves receiver and name on jump to miss. - GenerateStoreField(masm(), - object, - index, - transition, - rdx, rcx, rbx, - &miss); + GenerateStoreField(masm(), object, index, transition, rdx, rcx, rbx, &miss); // Handle store cache miss. __ bind(&miss); @@ -2525,39 +2431,38 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, __ Jump(ic, RelocInfo::CODE_TARGET); // Return the generated code. - return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); + return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); } -MaybeObject* KeyedStoreStubCompiler::CompileStoreElement(Map* receiver_map) { +Handle<Code> KeyedStoreStubCompiler::CompileStoreElement( + Handle<Map> receiver_map) { // ----------- S t a t e ------------- // -- rax : value // -- rcx : key // -- rdx : receiver // -- rsp[0] : return address // ----------------------------------- - Code* stub; + ElementsKind elements_kind = receiver_map->elements_kind(); bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; - MaybeObject* maybe_stub = - KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode(); - if (!maybe_stub->To(&stub)) return maybe_stub; - __ DispatchMap(rdx, - Handle<Map>(receiver_map), - Handle<Code>(stub), - DO_SMI_CHECK); + Handle<Code> stub = + KeyedStoreElementStub(is_js_array, elements_kind).GetCode(); + + __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK); Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); __ jmp(ic, RelocInfo::CODE_TARGET); // Return the generated code. - return GetCode(NORMAL, NULL); + return GetCode(NORMAL, factory()->empty_string()); } -MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic( - MapList* receiver_maps, - CodeList* handler_ics) { +Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic( + MapHandleList* receiver_maps, + CodeHandleList* handler_stubs, + MapHandleList* transitioned_maps) { // ----------- S t a t e ------------- // -- rax : value // -- rcx : key @@ -2565,18 +2470,22 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic( // -- rsp[0] : return address // ----------------------------------- Label miss; - __ JumpIfSmi(rdx, &miss); + __ JumpIfSmi(rdx, &miss, Label::kNear); - Register map_reg = rbx; - __ movq(map_reg, FieldOperand(rdx, HeapObject::kMapOffset)); + __ movq(rdi, FieldOperand(rdx, HeapObject::kMapOffset)); int receiver_count = receiver_maps->length(); - for (int current = 0; current < receiver_count; ++current) { + for (int i = 0; i < receiver_count; ++i) { // Check map and tail call if there's a match - Handle<Map> map(receiver_maps->at(current)); - __ Cmp(map_reg, map); - __ j(equal, - Handle<Code>(handler_ics->at(current)), - RelocInfo::CODE_TARGET); + __ Cmp(rdi, receiver_maps->at(i)); + if (transitioned_maps->at(i).is_null()) { + __ j(equal, handler_stubs->at(i), RelocInfo::CODE_TARGET); + } else { + Label next_map; + __ j(not_equal, &next_map, Label::kNear); + __ movq(rbx, transitioned_maps->at(i), RelocInfo::EMBEDDED_OBJECT); + __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET); + __ bind(&next_map); + } } __ bind(&miss); @@ -2584,13 +2493,13 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic( __ jmp(ic, RelocInfo::CODE_TARGET); // Return the generated code. - return GetCode(NORMAL, NULL, MEGAMORPHIC); + return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC); } -MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, - JSObject* object, - JSObject* last) { +Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name, + Handle<JSObject> object, + Handle<JSObject> last) { // ----------- S t a t e ------------- // -- rax : receiver // -- rcx : name @@ -2609,15 +2518,8 @@ MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, // If the last object in the prototype chain is a global object, // check that the global property cell is empty. if (last->IsGlobalObject()) { - MaybeObject* cell = GenerateCheckPropertyCell(masm(), - GlobalObject::cast(last), - name, - rdx, - &miss); - if (cell->IsFailure()) { - miss.Unuse(); - return cell; - } + GenerateCheckPropertyCell( + masm(), Handle<GlobalObject>::cast(last), name, rdx, &miss); } // Return undefined if maps of the full prototype chain are still the @@ -2629,14 +2531,14 @@ MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, GenerateLoadMiss(masm(), Code::LOAD_IC); // Return the generated code. - return GetCode(NONEXISTENT, heap()->empty_string()); + return GetCode(NONEXISTENT, factory()->empty_string()); } -MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object, - JSObject* holder, +Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object, + Handle<JSObject> holder, int index, - String* name) { + Handle<String> name) { // ----------- S t a t e ------------- // -- rax : receiver // -- rcx : name @@ -2653,24 +2555,19 @@ MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object, } -MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name, - JSObject* object, - JSObject* holder, - AccessorInfo* callback) { +Handle<Code> LoadStubCompiler::CompileLoadCallback( + Handle<String> name, + Handle<JSObject> object, + Handle<JSObject> holder, + Handle<AccessorInfo> callback) { // ----------- S t a t e ------------- // -- rax : receiver // -- rcx : name // -- rsp[0] : return address // ----------------------------------- Label miss; - - MaybeObject* result = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, - rdi, callback, name, &miss); - if (result->IsFailure()) { - miss.Unuse(); - return result; - } - + GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, rdi, callback, + name, &miss); __ bind(&miss); GenerateLoadMiss(masm(), Code::LOAD_IC); @@ -2679,10 +2576,10 @@ MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name, } -MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object, - JSObject* holder, - Object* value, - String* name) { +Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object, + Handle<JSObject> holder, + Handle<Object> value, + Handle<String> name) { // ----------- S t a t e ------------- // -- rax : receiver // -- rcx : name @@ -2699,32 +2596,22 @@ MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object, } -MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, - JSObject* holder, - String* name) { +Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> receiver, + Handle<JSObject> holder, + Handle<String> name) { // ----------- S t a t e ------------- // -- rax : receiver // -- rcx : name // -- rsp[0] : return address // ----------------------------------- Label miss; - - LookupResult lookup; + LookupResult lookup(isolate()); LookupPostInterceptor(holder, name, &lookup); // TODO(368): Compile in the whole chain: all the interceptors in // prototypes and ultimate answer. - GenerateLoadInterceptor(receiver, - holder, - &lookup, - rax, - rcx, - rdx, - rbx, - rdi, - name, - &miss); - + GenerateLoadInterceptor(receiver, holder, &lookup, rax, rcx, rdx, rbx, rdi, + name, &miss); __ bind(&miss); GenerateLoadMiss(masm(), Code::LOAD_IC); @@ -2733,11 +2620,12 @@ MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, } -MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object, - GlobalObject* holder, - JSGlobalPropertyCell* cell, - String* name, - bool is_dont_delete) { +Handle<Code> LoadStubCompiler::CompileLoadGlobal( + Handle<JSObject> object, + Handle<GlobalObject> holder, + Handle<JSGlobalPropertyCell> cell, + Handle<String> name, + bool is_dont_delete) { // ----------- S t a t e ------------- // -- rax : receiver // -- rcx : name @@ -2748,7 +2636,7 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object, // If the object is the holder then we know that it's a global // object which can only happen for contextual loads. In this case, // the receiver cannot be a smi. - if (object != holder) { + if (!object.is_identical_to(holder)) { __ JumpIfSmi(rax, &miss); } @@ -2756,7 +2644,7 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object, CheckPrototypes(object, rax, holder, rbx, rdx, rdi, name, &miss); // Get the value from the cell. - __ Move(rbx, Handle<JSGlobalPropertyCell>(cell)); + __ Move(rbx, cell); __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset)); // Check for deleted property if property can actually be deleted. @@ -2782,9 +2670,9 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object, } -MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name, - JSObject* receiver, - JSObject* holder, +Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name, + Handle<JSObject> receiver, + Handle<JSObject> holder, int index) { // ----------- S t a t e ------------- // -- rax : key @@ -2797,7 +2685,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name, __ IncrementCounter(counters->keyed_load_field(), 1); // Check that the name has not changed. - __ Cmp(rax, Handle<String>(name)); + __ Cmp(rax, name); __ j(not_equal, &miss); GenerateLoadField(receiver, holder, rdx, rbx, rcx, rdi, index, name, &miss); @@ -2811,34 +2699,27 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name, } -MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( - String* name, - JSObject* receiver, - JSObject* holder, - AccessorInfo* callback) { +Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback( + Handle<String> name, + Handle<JSObject> receiver, + Handle<JSObject> holder, + Handle<AccessorInfo> callback) { // ----------- S t a t e ------------- // -- rax : key // -- rdx : receiver // -- rsp[0] : return address // ----------------------------------- Label miss; - Counters* counters = isolate()->counters(); __ IncrementCounter(counters->keyed_load_callback(), 1); // Check that the name has not changed. - __ Cmp(rax, Handle<String>(name)); + __ Cmp(rax, name); __ j(not_equal, &miss); - MaybeObject* result = GenerateLoadCallback(receiver, holder, rdx, rax, rbx, - rcx, rdi, callback, name, &miss); - if (result->IsFailure()) { - miss.Unuse(); - return result; - } - + GenerateLoadCallback(receiver, holder, rdx, rax, rbx, rcx, rdi, callback, + name, &miss); __ bind(&miss); - __ DecrementCounter(counters->keyed_load_callback(), 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); @@ -2847,10 +2728,11 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( } -MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name, - JSObject* receiver, - JSObject* holder, - Object* value) { +Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant( + Handle<String> name, + Handle<JSObject> receiver, + Handle<JSObject> holder, + Handle<Object> value) { // ----------- S t a t e ------------- // -- rax : key // -- rdx : receiver @@ -2862,7 +2744,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name, __ IncrementCounter(counters->keyed_load_constant_function(), 1); // Check that the name has not changed. - __ Cmp(rax, Handle<String>(name)); + __ Cmp(rax, name); __ j(not_equal, &miss); GenerateLoadConstant(receiver, holder, rdx, rbx, rcx, rdi, @@ -2876,35 +2758,27 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name, } -MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, - JSObject* holder, - String* name) { +Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor( + Handle<JSObject> receiver, + Handle<JSObject> holder, + Handle<String> name) { // ----------- S t a t e ------------- // -- rax : key // -- rdx : receiver // -- rsp[0] : return address // ----------------------------------- Label miss; - Counters* counters = isolate()->counters(); __ IncrementCounter(counters->keyed_load_interceptor(), 1); // Check that the name has not changed. - __ Cmp(rax, Handle<String>(name)); + __ Cmp(rax, name); __ j(not_equal, &miss); - LookupResult lookup; + LookupResult lookup(isolate()); LookupPostInterceptor(holder, name, &lookup); - GenerateLoadInterceptor(receiver, - holder, - &lookup, - rdx, - rax, - rcx, - rbx, - rdi, - name, - &miss); + GenerateLoadInterceptor(receiver, holder, &lookup, rdx, rax, rcx, rbx, rdi, + name, &miss); __ bind(&miss); __ DecrementCounter(counters->keyed_load_interceptor(), 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); @@ -2914,7 +2788,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, } -MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { +Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength( + Handle<String> name) { // ----------- S t a t e ------------- // -- rax : key // -- rdx : receiver @@ -2926,7 +2801,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { __ IncrementCounter(counters->keyed_load_array_length(), 1); // Check that the name has not changed. - __ Cmp(rax, Handle<String>(name)); + __ Cmp(rax, name); __ j(not_equal, &miss); GenerateLoadArrayLength(masm(), rdx, rcx, &miss); @@ -2939,7 +2814,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { } -MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { +Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength( + Handle<String> name) { // ----------- S t a t e ------------- // -- rax : key // -- rdx : receiver @@ -2951,7 +2827,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { __ IncrementCounter(counters->keyed_load_string_length(), 1); // Check that the name has not changed. - __ Cmp(rax, Handle<String>(name)); + __ Cmp(rax, name); __ j(not_equal, &miss); GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss, true); @@ -2964,7 +2840,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { } -MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { +Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype( + Handle<String> name) { // ----------- S t a t e ------------- // -- rax : key // -- rdx : receiver @@ -2976,7 +2853,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { __ IncrementCounter(counters->keyed_load_function_prototype(), 1); // Check that the name has not changed. - __ Cmp(rax, Handle<String>(name)); + __ Cmp(rax, name); __ j(not_equal, &miss); GenerateLoadFunctionPrototype(masm(), rdx, rcx, rbx, &miss); @@ -2989,32 +2866,29 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { } -MaybeObject* KeyedLoadStubCompiler::CompileLoadElement(Map* receiver_map) { +Handle<Code> KeyedLoadStubCompiler::CompileLoadElement( + Handle<Map> receiver_map) { // ----------- S t a t e ------------- // -- rax : key // -- rdx : receiver // -- rsp[0] : return address // ----------------------------------- - Code* stub; ElementsKind elements_kind = receiver_map->elements_kind(); - MaybeObject* maybe_stub = KeyedLoadElementStub(elements_kind).TryGetCode(); - if (!maybe_stub->To(&stub)) return maybe_stub; - __ DispatchMap(rdx, - Handle<Map>(receiver_map), - Handle<Code>(stub), - DO_SMI_CHECK); + Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode(); + + __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK); Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss(); __ jmp(ic, RelocInfo::CODE_TARGET); // Return the generated code. - return GetCode(NORMAL, NULL); + return GetCode(NORMAL, factory()->empty_string()); } -MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic( - MapList* receiver_maps, - CodeList* handler_ics) { +Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic( + MapHandleList* receiver_maps, + CodeHandleList* handler_ics) { // ----------- S t a t e ------------- // -- rax : key // -- rdx : receiver @@ -3028,24 +2902,22 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic( int receiver_count = receiver_maps->length(); for (int current = 0; current < receiver_count; ++current) { // Check map and tail call if there's a match - Handle<Map> map(receiver_maps->at(current)); - __ Cmp(map_reg, map); - __ j(equal, - Handle<Code>(handler_ics->at(current)), - RelocInfo::CODE_TARGET); + __ Cmp(map_reg, receiver_maps->at(current)); + __ j(equal, handler_ics->at(current), RelocInfo::CODE_TARGET); } __ bind(&miss); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); // Return the generated code. - return GetCode(NORMAL, NULL, MEGAMORPHIC); + return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC); } // Specialized stub for constructing objects from functions which only have only // simple assignments of the form this.x = ...; in their body. -MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { +Handle<Code> ConstructStubCompiler::CompileConstructStub( + Handle<JSFunction> function) { // ----------- S t a t e ------------- // -- rax : argc // -- rdi : constructor @@ -3088,12 +2960,8 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { // rbx: initial map __ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset)); __ shl(rcx, Immediate(kPointerSizeLog2)); - __ AllocateInNewSpace(rcx, - rdx, - rcx, - no_reg, - &generic_stub_call, - NO_ALLOCATION_FLAGS); + __ AllocateInNewSpace(rcx, rdx, rcx, no_reg, + &generic_stub_call, NO_ALLOCATION_FLAGS); // Allocated the JSObject, now initialize the fields and add the heap tag. // rbx: initial map @@ -3118,7 +2986,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { // r9: first in-object property of the JSObject // Fill the initialized properties with a constant value or a passed argument // depending on the this.x = ...; assignment in the function. - SharedFunctionInfo* shared = function->shared(); + Handle<SharedFunctionInfo> shared(function->shared()); for (int i = 0; i < shared->this_property_assignments_count(); i++) { if (shared->IsThisPropertyAssignmentArgument(i)) { // Check if the argument assigned to the property is actually passed. @@ -3166,10 +3034,8 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { // Jump to the generic stub in case the specialized code cannot handle the // construction. __ bind(&generic_stub_call); - Code* code = - isolate()->builtins()->builtin(Builtins::kJSConstructStubGeneric); - Handle<Code> generic_construct_stub(code); - __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); + Handle<Code> code = isolate()->builtins()->JSConstructStubGeneric(); + __ Jump(code, RelocInfo::CODE_TARGET); // Return the generated code. return GetCode(); @@ -3436,6 +3302,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( __ movsd(Operand(rbx, rdi, times_8, 0), xmm0); break; case FAST_ELEMENTS: + case FAST_SMI_ONLY_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case DICTIONARY_ELEMENTS: case NON_STRICT_ARGUMENTS_ELEMENTS: @@ -3503,6 +3370,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( case EXTERNAL_FLOAT_ELEMENTS: case EXTERNAL_DOUBLE_ELEMENTS: case FAST_ELEMENTS: + case FAST_SMI_ONLY_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case DICTIONARY_ELEMENTS: case NON_STRICT_ARGUMENTS_ELEMENTS: @@ -3634,15 +3502,17 @@ void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement( } -void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, - bool is_js_array) { +void KeyedStoreStubCompiler::GenerateStoreFastElement( + MacroAssembler* masm, + bool is_js_array, + ElementsKind elements_kind) { // ----------- S t a t e ------------- // -- rax : value // -- rcx : key // -- rdx : receiver // -- rsp[0] : return address // ----------------------------------- - Label miss_force_generic; + Label miss_force_generic, transition_elements_kind; // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. @@ -3665,13 +3535,22 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, __ j(above_equal, &miss_force_generic); } - // Do the store and update the write barrier. Make sure to preserve - // the value in register eax. - __ movq(rdx, rax); - __ SmiToInteger32(rcx, rcx); - __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize), - rax); - __ RecordWrite(rdi, 0, rdx, rcx); + if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { + __ JumpIfNotSmi(rax, &transition_elements_kind); + __ SmiToInteger32(rcx, rcx); + __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize), + rax); + } else { + // Do the store and update the write barrier. + ASSERT(elements_kind == FAST_ELEMENTS); + __ SmiToInteger32(rcx, rcx); + __ lea(rcx, + FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize)); + __ movq(Operand(rcx, 0), rax); + // Make sure to preserve the value in register rax. + __ movq(rdx, rax); + __ RecordWrite(rdi, rcx, rdx, kDontSaveFPRegs); + } // Done. __ ret(0); @@ -3681,6 +3560,10 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, Handle<Code> ic_force_generic = masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); + + __ bind(&transition_elements_kind); + Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss(); + __ jmp(ic_miss, RelocInfo::CODE_TARGET); } @@ -3693,8 +3576,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( // -- rdx : receiver // -- rsp[0] : return address // ----------------------------------- - Label miss_force_generic, smi_value, is_nan, maybe_nan; - Label have_double_value, not_nan; + Label miss_force_generic, transition_elements_kind; // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. @@ -3715,50 +3597,9 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( __ j(above_equal, &miss_force_generic); // Handle smi values specially - __ JumpIfSmi(rax, &smi_value, Label::kNear); - - __ CheckMap(rax, - masm->isolate()->factory()->heap_number_map(), - &miss_force_generic, - DONT_DO_SMI_CHECK); - - // Double value, canonicalize NaN. - uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32); - __ cmpl(FieldOperand(rax, offset), - Immediate(kNaNOrInfinityLowerBoundUpper32)); - __ j(greater_equal, &maybe_nan, Label::kNear); - - __ bind(¬_nan); - __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); - __ bind(&have_double_value); - __ SmiToInteger32(rcx, rcx); - __ movsd(FieldOperand(rdi, rcx, times_8, FixedDoubleArray::kHeaderSize), - xmm0); - __ ret(0); - - __ bind(&maybe_nan); - // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise - // it's an Infinity, and the non-NaN code path applies. - __ j(greater, &is_nan, Label::kNear); - __ cmpl(FieldOperand(rax, HeapNumber::kValueOffset), Immediate(0)); - __ j(zero, ¬_nan); - __ bind(&is_nan); - // Convert all NaNs to the same canonical NaN value when they are stored in - // the double array. - __ Set(kScratchRegister, BitCast<uint64_t>( - FixedDoubleArray::canonical_not_the_hole_nan_as_double())); - __ movq(xmm0, kScratchRegister); - __ jmp(&have_double_value, Label::kNear); - - __ bind(&smi_value); - // Value is a smi. convert to a double and store. - // Preserve original value. - __ SmiToInteger32(rdx, rax); - __ push(rdx); - __ fild_s(Operand(rsp, 0)); - __ pop(rdx); __ SmiToInteger32(rcx, rcx); - __ fstp_d(FieldOperand(rdi, rcx, times_8, FixedDoubleArray::kHeaderSize)); + __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0, + &transition_elements_kind); __ ret(0); // Handle store cache miss, replacing the ic with the generic stub. @@ -3766,6 +3607,12 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( Handle<Code> ic_force_generic = masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); + + __ bind(&transition_elements_kind); + // Restore smi-tagging of rcx. + __ Integer32ToSmi(rcx, rcx); + Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss(); + __ jmp(ic_miss, RelocInfo::CODE_TARGET); } |