blob: 803281e24da36ac413be3687ce35a9d144c3d3d4 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/ic/handler-compiler.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006
Ben Murdoch097c5b22016-05-18 11:27:45 +01007#include "src/field-type.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008#include "src/ic/call-optimization.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/ic/ic-inl.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010010#include "src/ic/ic.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011#include "src/isolate-inl.h"
12#include "src/profiler/cpu-profiler.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013
14namespace v8 {
15namespace internal {
16
17
18Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name,
19 Handle<Map> stub_holder,
20 Code::Kind kind,
21 CacheHolderFlag cache_holder,
22 Code::StubType type) {
23 Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder);
24 Object* probe = stub_holder->FindInCodeCache(*name, flags);
25 if (probe->IsCode()) return handle(Code::cast(probe));
26 return Handle<Code>::null();
27}
28
29
30Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031 Handle<Name> name, Handle<Map> receiver_map) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032 Isolate* isolate = name->GetIsolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000033 if (receiver_map->prototype()->IsNull()) {
34 // TODO(jkummerow/verwaest): If there is no prototype and the property
35 // is nonexistent, introduce a builtin to handle this (fast properties
36 // -> return undefined, dictionary properties -> do negative lookup).
37 return Handle<Code>();
38 }
39 CacheHolderFlag flag;
40 Handle<Map> stub_holder_map =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000041 IC::GetHandlerCacheHolder(receiver_map, false, isolate, &flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000042
43 // If no dictionary mode objects are present in the prototype chain, the load
44 // nonexistent IC stub can be shared for all names for a given map and we use
45 // the empty string for the map cache in that case. If there are dictionary
46 // mode objects involved, we need to do negative lookups in the stub and
47 // therefore the stub will be specific to the name.
48 Handle<Name> cache_name =
49 receiver_map->is_dictionary_map()
50 ? name
51 : Handle<Name>::cast(isolate->factory()->nonexistent_symbol());
52 Handle<Map> current_map = stub_holder_map;
53 Handle<JSObject> last(JSObject::cast(receiver_map->prototype()));
54 while (true) {
55 if (current_map->is_dictionary_map()) cache_name = name;
56 if (current_map->prototype()->IsNull()) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000057 if (name->IsPrivate()) {
58 // TODO(verwaest): Use nonexistent_private_symbol.
59 cache_name = name;
Ben Murdoch097c5b22016-05-18 11:27:45 +010060 if (!current_map->has_hidden_prototype()) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000061 }
62
Ben Murdochb8a8cc12014-11-26 15:28:44 +000063 last = handle(JSObject::cast(current_map->prototype()));
64 current_map = handle(last->map());
65 }
66 // Compile the stub that is either shared for all names or
67 // name specific if there are global objects involved.
68 Handle<Code> handler = PropertyHandlerCompiler::Find(
69 cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST);
70 if (!handler.is_null()) return handler;
71
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000072 NamedLoadHandlerCompiler compiler(isolate, receiver_map, last, flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000073 handler = compiler.CompileLoadNonexistent(cache_name);
74 Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
75 return handler;
76}
77
78
79Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
80 Code::StubType type,
81 Handle<Name> name) {
82 Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder());
83 Handle<Code> code = GetCodeWithFlags(flags, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000084 PROFILE(isolate(), CodeCreateEvent(Logger::HANDLER_TAG, *code, *name));
85#ifdef DEBUG
86 code->VerifyEmbeddedObjects();
87#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000088 return code;
89}
90
91
Ben Murdochb8a8cc12014-11-26 15:28:44 +000092#define __ ACCESS_MASM(masm())
93
94
95Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
96 Handle<Name> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000097 Label* miss,
98 ReturnHolder return_what) {
99 PrototypeCheckType check_type = SKIP_RECEIVER;
100 int function_index = map()->IsPrimitiveMap()
101 ? map()->GetConstructorFunctionIndex()
102 : Map::kNoConstructorFunctionIndex;
103 if (function_index != Map::kNoConstructorFunctionIndex) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000104 GenerateDirectLoadGlobalFunctionPrototype(masm(), function_index,
105 scratch1(), miss);
106 Object* function = isolate()->native_context()->get(function_index);
107 Object* prototype = JSFunction::cast(function)->instance_prototype();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108 Handle<Map> map(JSObject::cast(prototype)->map());
109 set_map(map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000110 object_reg = scratch1();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111 check_type = CHECK_ALL_MAPS;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000112 }
113
114 // Check that the maps starting from the prototype haven't changed.
115 return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000116 miss, check_type, return_what);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000117}
118
119
120// Frontend for store uses the name register. It has to be restored before a
121// miss.
122Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg,
123 Handle<Name> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000124 Label* miss,
125 ReturnHolder return_what) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000126 return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000127 miss, SKIP_RECEIVER, return_what);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000128}
129
130
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400131Register PropertyHandlerCompiler::Frontend(Handle<Name> name) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400133 if (IC::ICUseVector(kind())) {
134 PushVectorAndSlot();
135 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000136 Register reg = FrontendHeader(receiver(), name, &miss, RETURN_HOLDER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000137 FrontendFooter(name, &miss);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400138 // The footer consumes the vector and slot from the stack if miss occurs.
139 if (IC::ICUseVector(kind())) {
140 DiscardVectorAndSlot();
141 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000142 return reg;
143}
144
145
146void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name,
147 Label* miss,
148 Register scratch1,
149 Register scratch2) {
150 Register holder_reg;
151 Handle<Map> last_map;
152 if (holder().is_null()) {
153 holder_reg = receiver();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000154 last_map = map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000155 // If |type| has null as its prototype, |holder()| is
156 // Handle<JSObject>::null().
157 DCHECK(last_map->prototype() == isolate()->heap()->null_value());
158 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159 last_map = handle(holder()->map());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000160 // This condition matches the branches below.
161 bool need_holder =
162 last_map->is_dictionary_map() && !last_map->IsJSGlobalObjectMap();
163 holder_reg =
164 FrontendHeader(receiver(), name, miss,
165 need_holder ? RETURN_HOLDER : DONT_RETURN_ANYTHING);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000166 }
167
168 if (last_map->is_dictionary_map()) {
169 if (last_map->IsJSGlobalObjectMap()) {
170 Handle<JSGlobalObject> global =
171 holder().is_null()
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000172 ? Handle<JSGlobalObject>::cast(isolate()->global_object())
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000173 : Handle<JSGlobalObject>::cast(holder());
174 GenerateCheckPropertyCell(masm(), global, name, scratch1, miss);
175 } else {
176 if (!name->IsUniqueName()) {
177 DCHECK(name->IsString());
178 name = factory()->InternalizeString(Handle<String>::cast(name));
179 }
180 DCHECK(holder().is_null() ||
181 holder()->property_dictionary()->FindEntry(name) ==
182 NameDictionary::kNotFound);
183 GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1,
184 scratch2);
185 }
186 }
187}
188
189
190Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name,
191 FieldIndex field) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400192 Register reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000193 __ Move(receiver(), reg);
194 LoadFieldStub stub(isolate(), field);
195 GenerateTailCall(masm(), stub.GetCode());
196 return GetCode(kind(), Code::FAST, name);
197}
198
199
200Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name,
201 int constant_index) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400202 Register reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000203 __ Move(receiver(), reg);
204 LoadConstantStub stub(isolate(), constant_index);
205 GenerateTailCall(masm(), stub.GetCode());
206 return GetCode(kind(), Code::FAST, name);
207}
208
209
210Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
211 Handle<Name> name) {
212 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400213 if (IC::ICUseVector(kind())) {
214 DCHECK(kind() == Code::LOAD_IC);
215 PushVectorAndSlot();
216 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000217 NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400218 if (IC::ICUseVector(kind())) {
219 DiscardVectorAndSlot();
220 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000221 GenerateLoadConstant(isolate()->factory()->undefined_value());
222 FrontendFooter(name, &miss);
223 return GetCode(kind(), Code::FAST, name);
224}
225
226
227Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100228 Handle<Name> name, Handle<AccessorInfo> callback) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400229 Register reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000230 GenerateLoadCallback(reg, callback);
231 return GetCode(kind(), Code::FAST, name);
232}
233
234
235Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000236 Handle<Name> name, const CallOptimization& call_optimization,
237 int accessor_index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000238 DCHECK(call_optimization.is_simple_api_call());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239 Register holder = Frontend(name);
240 GenerateApiAccessorCall(masm(), call_optimization, map(), receiver(),
241 scratch2(), false, no_reg, holder, accessor_index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000242 return GetCode(kind(), Code::FAST, name);
243}
244
245
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400246void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) {
247 if (IC::ICUseVector(kind())) {
248 if (holder_reg.is(receiver())) {
249 PushVectorAndSlot();
250 } else {
251 DCHECK(holder_reg.is(scratch1()));
252 PushVectorAndSlot(scratch2(), scratch3());
253 }
254 }
255}
256
257
258void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg,
259 PopMode mode) {
260 if (IC::ICUseVector(kind())) {
261 if (mode == DISCARD) {
262 DiscardVectorAndSlot();
263 } else {
264 if (holder_reg.is(receiver())) {
265 PopVectorAndSlot();
266 } else {
267 DCHECK(holder_reg.is(scratch1()));
268 PopVectorAndSlot(scratch2(), scratch3());
269 }
270 }
271 }
272}
273
274
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000275Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
276 LookupIterator* it) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000277 // So far the most popular follow ups for interceptor loads are DATA and
Ben Murdoch097c5b22016-05-18 11:27:45 +0100278 // AccessorInfo, so inline only them. Other cases may be added
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000279 // later.
280 bool inline_followup = false;
281 switch (it->state()) {
282 case LookupIterator::TRANSITION:
283 UNREACHABLE();
284 case LookupIterator::ACCESS_CHECK:
285 case LookupIterator::INTERCEPTOR:
286 case LookupIterator::JSPROXY:
287 case LookupIterator::NOT_FOUND:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000288 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000289 break;
290 case LookupIterator::DATA:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400291 inline_followup =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000292 it->property_details().type() == DATA && !it->is_dictionary_holder();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000293 break;
294 case LookupIterator::ACCESSOR: {
295 Handle<Object> accessors = it->GetAccessors();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100296 if (accessors->IsAccessorInfo()) {
297 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
298 inline_followup =
299 info->getter() != NULL &&
300 AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000301 } else if (accessors->IsAccessorPair()) {
302 Handle<JSObject> property_holder(it->GetHolder<JSObject>());
303 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
304 isolate());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100305 if (!(getter->IsJSFunction() || getter->IsFunctionTemplateInfo())) {
306 break;
307 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000308 if (!property_holder->HasFastProperties()) break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100309 CallOptimization call_optimization(getter);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000310 Handle<Map> receiver_map = map();
311 inline_followup = call_optimization.is_simple_api_call() &&
312 call_optimization.IsCompatibleReceiverMap(
313 receiver_map, property_holder);
314 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000315 }
316 }
317
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400318 Label miss;
319 InterceptorVectorSlotPush(receiver());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000320 bool lost_holder_register = false;
321 auto holder_orig = holder();
322 // non masking interceptors must check the entire chain, so temporarily reset
323 // the holder to be that last element for the FrontendHeader call.
324 if (holder()->GetNamedInterceptor()->non_masking()) {
325 DCHECK(!inline_followup);
326 JSObject* last = *holder();
327 PrototypeIterator iter(isolate(), last);
328 while (!iter.IsAtEnd()) {
329 lost_holder_register = true;
330 // Casting to JSObject is fine here. The LookupIterator makes sure to
331 // look behind non-masking interceptors during the original lookup, and
332 // we wouldn't try to compile a handler if there was a Proxy anywhere.
333 last = iter.GetCurrent<JSObject>();
334 iter.Advance();
335 }
336 auto last_handle = handle(last);
337 set_holder(last_handle);
338 }
339 Register reg = FrontendHeader(receiver(), it->name(), &miss, RETURN_HOLDER);
340 // Reset the holder so further calculations are correct.
341 set_holder(holder_orig);
342 if (lost_holder_register) {
343 if (*it->GetReceiver() == *holder()) {
344 reg = receiver();
345 } else {
346 // Reload lost holder register.
347 auto cell = isolate()->factory()->NewWeakCell(holder());
348 __ LoadWeakValue(reg, cell, &miss);
349 }
350 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400351 FrontendFooter(it->name(), &miss);
352 InterceptorVectorSlotPop(reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000353 if (inline_followup) {
354 // TODO(368): Compile in the whole chain: all the interceptors in
355 // prototypes and ultimate answer.
356 GenerateLoadInterceptorWithFollowup(it, reg);
357 } else {
358 GenerateLoadInterceptor(reg);
359 }
360 return GetCode(kind(), Code::FAST, it->name());
361}
362
363
364void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
365 LookupIterator* it, Register interceptor_reg) {
366 Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>());
367
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000368 Handle<Map> holder_map(holder()->map());
369 set_map(holder_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000370 set_holder(real_named_property_holder);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400371
372 Label miss;
373 InterceptorVectorSlotPush(interceptor_reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000374 Register reg =
375 FrontendHeader(interceptor_reg, it->name(), &miss, RETURN_HOLDER);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400376 FrontendFooter(it->name(), &miss);
377 // We discard the vector and slot now because we don't miss below this point.
378 InterceptorVectorSlotPop(reg, DISCARD);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000379
380 switch (it->state()) {
381 case LookupIterator::ACCESS_CHECK:
382 case LookupIterator::INTERCEPTOR:
383 case LookupIterator::JSPROXY:
384 case LookupIterator::NOT_FOUND:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000385 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000386 case LookupIterator::TRANSITION:
387 UNREACHABLE();
388 case LookupIterator::DATA: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000389 DCHECK_EQ(DATA, it->property_details().type());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000390 __ Move(receiver(), reg);
391 LoadFieldStub stub(isolate(), it->GetFieldIndex());
392 GenerateTailCall(masm(), stub.GetCode());
393 break;
394 }
395 case LookupIterator::ACCESSOR:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100396 if (it->GetAccessors()->IsAccessorInfo()) {
397 Handle<AccessorInfo> info =
398 Handle<AccessorInfo>::cast(it->GetAccessors());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000399 DCHECK_NOT_NULL(info->getter());
400 GenerateLoadCallback(reg, info);
401 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100402 Handle<Object> function = handle(
403 AccessorPair::cast(*it->GetAccessors())->getter(), isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000404 CallOptimization call_optimization(function);
405 GenerateApiAccessorCall(masm(), call_optimization, holder_map,
406 receiver(), scratch2(), false, no_reg, reg,
407 it->GetAccessorIndex());
408 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000409 }
410}
411
412
413Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000414 Handle<Name> name, int accessor_index, int expected_arguments) {
415 Register holder = Frontend(name);
416 GenerateLoadViaGetter(masm(), map(), receiver(), holder, accessor_index,
417 expected_arguments, scratch2());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000418 return GetCode(kind(), Code::FAST, name);
419}
420
421
422// TODO(verwaest): Cleanup. holder() is actually the receiver.
423Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
424 Handle<Map> transition, Handle<Name> name) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400425 Label miss;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000426
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000427 PushVectorAndSlot();
428
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000429 // Check that we are allowed to write this.
430 bool is_nonexistent = holder()->map() == transition->GetBackPointer();
431 if (is_nonexistent) {
432 // Find the top object.
433 Handle<JSObject> last;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000434 PrototypeIterator::WhereToEnd end =
435 name->IsPrivate() ? PrototypeIterator::END_AT_NON_HIDDEN
436 : PrototypeIterator::END_AT_NULL;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100437 PrototypeIterator iter(isolate(), holder(),
438 PrototypeIterator::START_AT_PROTOTYPE, end);
439 while (!iter.IsAtEnd()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000440 last = PrototypeIterator::GetCurrent<JSObject>(iter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000441 iter.Advance();
442 }
443 if (!last.is_null()) set_holder(last);
444 NonexistentFrontendHeader(name, &miss, scratch1(), scratch2());
445 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000446 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000447 DCHECK(holder()->HasFastProperties());
448 }
449
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400450 int descriptor = transition->LastAdded();
451 Handle<DescriptorArray> descriptors(transition->instance_descriptors());
452 PropertyDetails details = descriptors->GetDetails(descriptor);
453 Representation representation = details.representation();
454 DCHECK(!representation.IsNone());
455
456 // Stub is never generated for objects that require access checks.
457 DCHECK(!transition->is_access_check_needed());
458
459 // Call to respective StoreTransitionStub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000460 bool virtual_args = StoreTransitionHelper::HasVirtualSlotArg();
461 Register map_reg = StoreTransitionHelper::MapRegister();
462
463 if (details.type() == DATA_CONSTANT) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400464 DCHECK(descriptors->GetValue(descriptor)->IsJSFunction());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000465 Register tmp =
466 virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
467 GenerateRestoreMap(transition, tmp, scratch2(), &miss);
468 GenerateConstantCheck(tmp, descriptor, value(), scratch2(), &miss);
469 if (virtual_args) {
470 // This will move the map from tmp into map_reg.
471 RearrangeVectorAndSlot(tmp, map_reg);
472 } else {
473 PopVectorAndSlot();
474 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400475 GenerateRestoreName(name);
476 StoreTransitionStub stub(isolate());
477 GenerateTailCall(masm(), stub.GetCode());
478
479 } else {
480 if (representation.IsHeapObject()) {
481 GenerateFieldTypeChecks(descriptors->GetFieldType(descriptor), value(),
482 &miss);
483 }
484 StoreTransitionStub::StoreMode store_mode =
485 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0
486 ? StoreTransitionStub::ExtendStorageAndStoreMapAndValue
487 : StoreTransitionStub::StoreMapAndValue;
488
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000489 Register tmp =
490 virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
491 GenerateRestoreMap(transition, tmp, scratch2(), &miss);
492 if (virtual_args) {
493 RearrangeVectorAndSlot(tmp, map_reg);
494 } else {
495 PopVectorAndSlot();
496 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400497 GenerateRestoreName(name);
498 StoreTransitionStub stub(isolate(),
499 FieldIndex::ForDescriptor(*transition, descriptor),
500 representation, store_mode);
501 GenerateTailCall(masm(), stub.GetCode());
502 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000503
504 GenerateRestoreName(&miss, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000505 PopVectorAndSlot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000506 TailCallBuiltin(masm(), MissBuiltin(kind()));
507
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000508 return GetCode(kind(), Code::FAST, name);
509}
510
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000511bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100512 FieldType* field_type) const {
513 return field_type->IsClass();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000514}
515
516
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000517Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) {
518 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400519 DCHECK(it->representation().IsHeapObject());
520
Ben Murdoch097c5b22016-05-18 11:27:45 +0100521 FieldType* field_type = *it->GetFieldType();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000522 bool need_save_restore = false;
523 if (RequiresFieldTypeChecks(field_type)) {
524 need_save_restore = IC::ICUseVector(kind());
525 if (need_save_restore) PushVectorAndSlot();
526 GenerateFieldTypeChecks(field_type, value(), &miss);
527 if (need_save_restore) PopVectorAndSlot();
528 }
529
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400530 StoreFieldStub stub(isolate(), it->GetFieldIndex(), it->representation());
531 GenerateTailCall(masm(), stub.GetCode());
532
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000533 __ bind(&miss);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000534 if (need_save_restore) PopVectorAndSlot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000535 TailCallBuiltin(masm(), MissBuiltin(kind()));
536 return GetCode(kind(), Code::FAST, it->name());
537}
538
539
540Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000541 Handle<JSObject> object, Handle<Name> name, int accessor_index,
542 int expected_arguments) {
543 Register holder = Frontend(name);
544 GenerateStoreViaSetter(masm(), map(), receiver(), holder, accessor_index,
545 expected_arguments, scratch2());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000546
547 return GetCode(kind(), Code::FAST, name);
548}
549
550
551Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
552 Handle<JSObject> object, Handle<Name> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000553 const CallOptimization& call_optimization, int accessor_index) {
554 Register holder = Frontend(name);
555 GenerateApiAccessorCall(masm(), call_optimization, handle(object->map()),
556 receiver(), scratch2(), true, value(), holder,
557 accessor_index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000558 return GetCode(kind(), Code::FAST, name);
559}
560
561
562#undef __
563
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000564void ElementHandlerCompiler::CompileElementHandlers(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100565 MapHandleList* receiver_maps, CodeHandleList* handlers) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000566 for (int i = 0; i < receiver_maps->length(); ++i) {
567 Handle<Map> receiver_map = receiver_maps->at(i);
568 Handle<Code> cached_stub;
569
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400570 if (receiver_map->IsStringMap()) {
571 cached_stub = LoadIndexedStringStub(isolate()).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000572 } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100573 cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000574 } else {
575 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
576 ElementsKind elements_kind = receiver_map->elements_kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000577
578 // No need to check for an elements-free prototype chain here, the
579 // generated stub code needs to check that dynamically anyway.
580 bool convert_hole_to_undefined =
581 (is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
Ben Murdoch097c5b22016-05-18 11:27:45 +0100582 *receiver_map == isolate()->get_initial_js_array_map(elements_kind));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000583
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000584 if (receiver_map->has_indexed_interceptor()) {
585 cached_stub = LoadIndexedInterceptorStub(isolate()).GetCode();
586 } else if (IsSloppyArgumentsElements(elements_kind)) {
587 cached_stub = KeyedLoadSloppyArgumentsStub(isolate()).GetCode();
588 } else if (IsFastElementsKind(elements_kind) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000589 IsFixedTypedArrayElementsKind(elements_kind)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000590 cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind,
591 convert_hole_to_undefined).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000592 } else {
593 DCHECK(elements_kind == DICTIONARY_ELEMENTS);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100594 LoadICState state = LoadICState(kNoExtraICState);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000595 cached_stub = LoadDictionaryElementStub(isolate(), state).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000596 }
597 }
598
599 handlers->Add(cached_stub);
600 }
601}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000602} // namespace internal
603} // namespace v8