blob: 714888c8b3ef2626e82a64194a3f03b51f3aff38 [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 Murdochda12d292016-06-02 14:46:10 +010084 PROFILE(isolate(), CodeCreateEvent(Logger::HANDLER_TAG,
85 AbstractCode::cast(*code), *name));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000086#ifdef DEBUG
87 code->VerifyEmbeddedObjects();
88#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089 return code;
90}
91
92
Ben Murdochb8a8cc12014-11-26 15:28:44 +000093#define __ ACCESS_MASM(masm())
94
95
96Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
97 Handle<Name> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000098 Label* miss,
99 ReturnHolder return_what) {
100 PrototypeCheckType check_type = SKIP_RECEIVER;
101 int function_index = map()->IsPrimitiveMap()
102 ? map()->GetConstructorFunctionIndex()
103 : Map::kNoConstructorFunctionIndex;
104 if (function_index != Map::kNoConstructorFunctionIndex) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000105 GenerateDirectLoadGlobalFunctionPrototype(masm(), function_index,
106 scratch1(), miss);
107 Object* function = isolate()->native_context()->get(function_index);
108 Object* prototype = JSFunction::cast(function)->instance_prototype();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000109 Handle<Map> map(JSObject::cast(prototype)->map());
110 set_map(map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000111 object_reg = scratch1();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000112 check_type = CHECK_ALL_MAPS;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000113 }
114
115 // Check that the maps starting from the prototype haven't changed.
116 return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000117 miss, check_type, return_what);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000118}
119
120
121// Frontend for store uses the name register. It has to be restored before a
122// miss.
123Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg,
124 Handle<Name> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000125 Label* miss,
126 ReturnHolder return_what) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000127 return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000128 miss, SKIP_RECEIVER, return_what);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129}
130
131
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400132Register PropertyHandlerCompiler::Frontend(Handle<Name> name) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000133 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400134 if (IC::ICUseVector(kind())) {
135 PushVectorAndSlot();
136 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000137 Register reg = FrontendHeader(receiver(), name, &miss, RETURN_HOLDER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000138 FrontendFooter(name, &miss);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400139 // The footer consumes the vector and slot from the stack if miss occurs.
140 if (IC::ICUseVector(kind())) {
141 DiscardVectorAndSlot();
142 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000143 return reg;
144}
145
146
147void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name,
148 Label* miss,
149 Register scratch1,
150 Register scratch2) {
151 Register holder_reg;
152 Handle<Map> last_map;
153 if (holder().is_null()) {
154 holder_reg = receiver();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000155 last_map = map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000156 // If |type| has null as its prototype, |holder()| is
157 // Handle<JSObject>::null().
158 DCHECK(last_map->prototype() == isolate()->heap()->null_value());
159 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000160 last_map = handle(holder()->map());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000161 // This condition matches the branches below.
162 bool need_holder =
163 last_map->is_dictionary_map() && !last_map->IsJSGlobalObjectMap();
164 holder_reg =
165 FrontendHeader(receiver(), name, miss,
166 need_holder ? RETURN_HOLDER : DONT_RETURN_ANYTHING);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167 }
168
169 if (last_map->is_dictionary_map()) {
170 if (last_map->IsJSGlobalObjectMap()) {
171 Handle<JSGlobalObject> global =
172 holder().is_null()
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000173 ? Handle<JSGlobalObject>::cast(isolate()->global_object())
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000174 : Handle<JSGlobalObject>::cast(holder());
175 GenerateCheckPropertyCell(masm(), global, name, scratch1, miss);
176 } else {
177 if (!name->IsUniqueName()) {
178 DCHECK(name->IsString());
179 name = factory()->InternalizeString(Handle<String>::cast(name));
180 }
181 DCHECK(holder().is_null() ||
182 holder()->property_dictionary()->FindEntry(name) ==
183 NameDictionary::kNotFound);
184 GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1,
185 scratch2);
186 }
187 }
188}
189
190
191Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name,
192 FieldIndex field) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400193 Register reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000194 __ Move(receiver(), reg);
195 LoadFieldStub stub(isolate(), field);
196 GenerateTailCall(masm(), stub.GetCode());
197 return GetCode(kind(), Code::FAST, name);
198}
199
200
201Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name,
202 int constant_index) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400203 Register reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000204 __ Move(receiver(), reg);
205 LoadConstantStub stub(isolate(), constant_index);
206 GenerateTailCall(masm(), stub.GetCode());
207 return GetCode(kind(), Code::FAST, name);
208}
209
210
211Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
212 Handle<Name> name) {
213 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400214 if (IC::ICUseVector(kind())) {
215 DCHECK(kind() == Code::LOAD_IC);
216 PushVectorAndSlot();
217 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000218 NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400219 if (IC::ICUseVector(kind())) {
220 DiscardVectorAndSlot();
221 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000222 GenerateLoadConstant(isolate()->factory()->undefined_value());
223 FrontendFooter(name, &miss);
224 return GetCode(kind(), Code::FAST, name);
225}
226
227
228Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100229 Handle<Name> name, Handle<AccessorInfo> callback) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400230 Register reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000231 GenerateLoadCallback(reg, callback);
232 return GetCode(kind(), Code::FAST, name);
233}
234
235
236Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000237 Handle<Name> name, const CallOptimization& call_optimization,
238 int accessor_index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000239 DCHECK(call_optimization.is_simple_api_call());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000240 Register holder = Frontend(name);
241 GenerateApiAccessorCall(masm(), call_optimization, map(), receiver(),
242 scratch2(), false, no_reg, holder, accessor_index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000243 return GetCode(kind(), Code::FAST, name);
244}
245
246
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400247void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) {
248 if (IC::ICUseVector(kind())) {
249 if (holder_reg.is(receiver())) {
250 PushVectorAndSlot();
251 } else {
252 DCHECK(holder_reg.is(scratch1()));
253 PushVectorAndSlot(scratch2(), scratch3());
254 }
255 }
256}
257
258
259void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg,
260 PopMode mode) {
261 if (IC::ICUseVector(kind())) {
262 if (mode == DISCARD) {
263 DiscardVectorAndSlot();
264 } else {
265 if (holder_reg.is(receiver())) {
266 PopVectorAndSlot();
267 } else {
268 DCHECK(holder_reg.is(scratch1()));
269 PopVectorAndSlot(scratch2(), scratch3());
270 }
271 }
272 }
273}
274
275
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000276Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
277 LookupIterator* it) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000278 // So far the most popular follow ups for interceptor loads are DATA and
Ben Murdoch097c5b22016-05-18 11:27:45 +0100279 // AccessorInfo, so inline only them. Other cases may be added
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000280 // later.
281 bool inline_followup = false;
282 switch (it->state()) {
283 case LookupIterator::TRANSITION:
284 UNREACHABLE();
285 case LookupIterator::ACCESS_CHECK:
286 case LookupIterator::INTERCEPTOR:
287 case LookupIterator::JSPROXY:
288 case LookupIterator::NOT_FOUND:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000289 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000290 break;
291 case LookupIterator::DATA:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400292 inline_followup =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000293 it->property_details().type() == DATA && !it->is_dictionary_holder();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000294 break;
295 case LookupIterator::ACCESSOR: {
296 Handle<Object> accessors = it->GetAccessors();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100297 if (accessors->IsAccessorInfo()) {
298 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
299 inline_followup =
300 info->getter() != NULL &&
301 AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000302 } else if (accessors->IsAccessorPair()) {
303 Handle<JSObject> property_holder(it->GetHolder<JSObject>());
304 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
305 isolate());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100306 if (!(getter->IsJSFunction() || getter->IsFunctionTemplateInfo())) {
307 break;
308 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000309 if (!property_holder->HasFastProperties()) break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100310 CallOptimization call_optimization(getter);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000311 Handle<Map> receiver_map = map();
312 inline_followup = call_optimization.is_simple_api_call() &&
313 call_optimization.IsCompatibleReceiverMap(
314 receiver_map, property_holder);
315 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000316 }
317 }
318
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400319 Label miss;
320 InterceptorVectorSlotPush(receiver());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000321 bool lost_holder_register = false;
322 auto holder_orig = holder();
323 // non masking interceptors must check the entire chain, so temporarily reset
324 // the holder to be that last element for the FrontendHeader call.
325 if (holder()->GetNamedInterceptor()->non_masking()) {
326 DCHECK(!inline_followup);
327 JSObject* last = *holder();
328 PrototypeIterator iter(isolate(), last);
329 while (!iter.IsAtEnd()) {
330 lost_holder_register = true;
331 // Casting to JSObject is fine here. The LookupIterator makes sure to
332 // look behind non-masking interceptors during the original lookup, and
333 // we wouldn't try to compile a handler if there was a Proxy anywhere.
334 last = iter.GetCurrent<JSObject>();
335 iter.Advance();
336 }
337 auto last_handle = handle(last);
338 set_holder(last_handle);
339 }
340 Register reg = FrontendHeader(receiver(), it->name(), &miss, RETURN_HOLDER);
341 // Reset the holder so further calculations are correct.
342 set_holder(holder_orig);
343 if (lost_holder_register) {
344 if (*it->GetReceiver() == *holder()) {
345 reg = receiver();
346 } else {
347 // Reload lost holder register.
348 auto cell = isolate()->factory()->NewWeakCell(holder());
349 __ LoadWeakValue(reg, cell, &miss);
350 }
351 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400352 FrontendFooter(it->name(), &miss);
353 InterceptorVectorSlotPop(reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000354 if (inline_followup) {
355 // TODO(368): Compile in the whole chain: all the interceptors in
356 // prototypes and ultimate answer.
357 GenerateLoadInterceptorWithFollowup(it, reg);
358 } else {
359 GenerateLoadInterceptor(reg);
360 }
361 return GetCode(kind(), Code::FAST, it->name());
362}
363
364
365void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
366 LookupIterator* it, Register interceptor_reg) {
367 Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>());
368
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000369 Handle<Map> holder_map(holder()->map());
370 set_map(holder_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000371 set_holder(real_named_property_holder);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400372
373 Label miss;
374 InterceptorVectorSlotPush(interceptor_reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000375 Register reg =
376 FrontendHeader(interceptor_reg, it->name(), &miss, RETURN_HOLDER);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400377 FrontendFooter(it->name(), &miss);
378 // We discard the vector and slot now because we don't miss below this point.
379 InterceptorVectorSlotPop(reg, DISCARD);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000380
381 switch (it->state()) {
382 case LookupIterator::ACCESS_CHECK:
383 case LookupIterator::INTERCEPTOR:
384 case LookupIterator::JSPROXY:
385 case LookupIterator::NOT_FOUND:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000386 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000387 case LookupIterator::TRANSITION:
388 UNREACHABLE();
389 case LookupIterator::DATA: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000390 DCHECK_EQ(DATA, it->property_details().type());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000391 __ Move(receiver(), reg);
392 LoadFieldStub stub(isolate(), it->GetFieldIndex());
393 GenerateTailCall(masm(), stub.GetCode());
394 break;
395 }
396 case LookupIterator::ACCESSOR:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100397 if (it->GetAccessors()->IsAccessorInfo()) {
398 Handle<AccessorInfo> info =
399 Handle<AccessorInfo>::cast(it->GetAccessors());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000400 DCHECK_NOT_NULL(info->getter());
401 GenerateLoadCallback(reg, info);
402 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100403 Handle<Object> function = handle(
404 AccessorPair::cast(*it->GetAccessors())->getter(), isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000405 CallOptimization call_optimization(function);
406 GenerateApiAccessorCall(masm(), call_optimization, holder_map,
407 receiver(), scratch2(), false, no_reg, reg,
408 it->GetAccessorIndex());
409 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000410 }
411}
412
413
414Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415 Handle<Name> name, int accessor_index, int expected_arguments) {
416 Register holder = Frontend(name);
417 GenerateLoadViaGetter(masm(), map(), receiver(), holder, accessor_index,
418 expected_arguments, scratch2());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000419 return GetCode(kind(), Code::FAST, name);
420}
421
422
423// TODO(verwaest): Cleanup. holder() is actually the receiver.
424Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
425 Handle<Map> transition, Handle<Name> name) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400426 Label miss;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000427
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000428 PushVectorAndSlot();
429
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000430 // Check that we are allowed to write this.
431 bool is_nonexistent = holder()->map() == transition->GetBackPointer();
432 if (is_nonexistent) {
433 // Find the top object.
434 Handle<JSObject> last;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000435 PrototypeIterator::WhereToEnd end =
436 name->IsPrivate() ? PrototypeIterator::END_AT_NON_HIDDEN
437 : PrototypeIterator::END_AT_NULL;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100438 PrototypeIterator iter(isolate(), holder(),
439 PrototypeIterator::START_AT_PROTOTYPE, end);
440 while (!iter.IsAtEnd()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000441 last = PrototypeIterator::GetCurrent<JSObject>(iter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000442 iter.Advance();
443 }
444 if (!last.is_null()) set_holder(last);
445 NonexistentFrontendHeader(name, &miss, scratch1(), scratch2());
446 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000448 DCHECK(holder()->HasFastProperties());
449 }
450
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400451 int descriptor = transition->LastAdded();
452 Handle<DescriptorArray> descriptors(transition->instance_descriptors());
453 PropertyDetails details = descriptors->GetDetails(descriptor);
454 Representation representation = details.representation();
455 DCHECK(!representation.IsNone());
456
457 // Stub is never generated for objects that require access checks.
458 DCHECK(!transition->is_access_check_needed());
459
460 // Call to respective StoreTransitionStub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000461 bool virtual_args = StoreTransitionHelper::HasVirtualSlotArg();
462 Register map_reg = StoreTransitionHelper::MapRegister();
463
464 if (details.type() == DATA_CONSTANT) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400465 DCHECK(descriptors->GetValue(descriptor)->IsJSFunction());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000466 Register tmp =
467 virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
468 GenerateRestoreMap(transition, tmp, scratch2(), &miss);
469 GenerateConstantCheck(tmp, descriptor, value(), scratch2(), &miss);
470 if (virtual_args) {
471 // This will move the map from tmp into map_reg.
472 RearrangeVectorAndSlot(tmp, map_reg);
473 } else {
474 PopVectorAndSlot();
475 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400476 GenerateRestoreName(name);
477 StoreTransitionStub stub(isolate());
478 GenerateTailCall(masm(), stub.GetCode());
479
480 } else {
481 if (representation.IsHeapObject()) {
482 GenerateFieldTypeChecks(descriptors->GetFieldType(descriptor), value(),
483 &miss);
484 }
485 StoreTransitionStub::StoreMode store_mode =
486 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0
487 ? StoreTransitionStub::ExtendStorageAndStoreMapAndValue
488 : StoreTransitionStub::StoreMapAndValue;
489
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490 Register tmp =
491 virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
492 GenerateRestoreMap(transition, tmp, scratch2(), &miss);
493 if (virtual_args) {
494 RearrangeVectorAndSlot(tmp, map_reg);
495 } else {
496 PopVectorAndSlot();
497 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400498 GenerateRestoreName(name);
499 StoreTransitionStub stub(isolate(),
500 FieldIndex::ForDescriptor(*transition, descriptor),
501 representation, store_mode);
502 GenerateTailCall(masm(), stub.GetCode());
503 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000504
505 GenerateRestoreName(&miss, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000506 PopVectorAndSlot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000507 TailCallBuiltin(masm(), MissBuiltin(kind()));
508
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000509 return GetCode(kind(), Code::FAST, name);
510}
511
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000512bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100513 FieldType* field_type) const {
514 return field_type->IsClass();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000515}
516
517
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000518Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) {
519 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400520 DCHECK(it->representation().IsHeapObject());
521
Ben Murdoch097c5b22016-05-18 11:27:45 +0100522 FieldType* field_type = *it->GetFieldType();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000523 bool need_save_restore = false;
524 if (RequiresFieldTypeChecks(field_type)) {
525 need_save_restore = IC::ICUseVector(kind());
526 if (need_save_restore) PushVectorAndSlot();
527 GenerateFieldTypeChecks(field_type, value(), &miss);
528 if (need_save_restore) PopVectorAndSlot();
529 }
530
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400531 StoreFieldStub stub(isolate(), it->GetFieldIndex(), it->representation());
532 GenerateTailCall(masm(), stub.GetCode());
533
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000534 __ bind(&miss);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000535 if (need_save_restore) PopVectorAndSlot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000536 TailCallBuiltin(masm(), MissBuiltin(kind()));
537 return GetCode(kind(), Code::FAST, it->name());
538}
539
540
541Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000542 Handle<JSObject> object, Handle<Name> name, int accessor_index,
543 int expected_arguments) {
544 Register holder = Frontend(name);
545 GenerateStoreViaSetter(masm(), map(), receiver(), holder, accessor_index,
546 expected_arguments, scratch2());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000547
548 return GetCode(kind(), Code::FAST, name);
549}
550
551
552Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
553 Handle<JSObject> object, Handle<Name> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000554 const CallOptimization& call_optimization, int accessor_index) {
555 Register holder = Frontend(name);
556 GenerateApiAccessorCall(masm(), call_optimization, handle(object->map()),
557 receiver(), scratch2(), true, value(), holder,
558 accessor_index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000559 return GetCode(kind(), Code::FAST, name);
560}
561
562
563#undef __
564
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000565void ElementHandlerCompiler::CompileElementHandlers(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100566 MapHandleList* receiver_maps, CodeHandleList* handlers) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000567 for (int i = 0; i < receiver_maps->length(); ++i) {
568 Handle<Map> receiver_map = receiver_maps->at(i);
569 Handle<Code> cached_stub;
570
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400571 if (receiver_map->IsStringMap()) {
572 cached_stub = LoadIndexedStringStub(isolate()).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000573 } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100574 cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575 } else {
576 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
577 ElementsKind elements_kind = receiver_map->elements_kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000578
579 // No need to check for an elements-free prototype chain here, the
580 // generated stub code needs to check that dynamically anyway.
581 bool convert_hole_to_undefined =
582 (is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
Ben Murdoch097c5b22016-05-18 11:27:45 +0100583 *receiver_map == isolate()->get_initial_js_array_map(elements_kind));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000584
Ben Murdochda12d292016-06-02 14:46:10 +0100585 if (receiver_map->has_indexed_interceptor() &&
586 !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined() &&
587 !receiver_map->GetIndexedInterceptor()->non_masking()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000588 cached_stub = LoadIndexedInterceptorStub(isolate()).GetCode();
589 } else if (IsSloppyArgumentsElements(elements_kind)) {
590 cached_stub = KeyedLoadSloppyArgumentsStub(isolate()).GetCode();
591 } else if (IsFastElementsKind(elements_kind) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000592 IsFixedTypedArrayElementsKind(elements_kind)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000593 cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind,
594 convert_hole_to_undefined).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000595 } else {
596 DCHECK(elements_kind == DICTIONARY_ELEMENTS);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100597 LoadICState state = LoadICState(kNoExtraICState);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000598 cached_stub = LoadDictionaryElementStub(isolate(), state).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000599 }
600 }
601
602 handlers->Add(cached_stub);
603 }
604}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000605} // namespace internal
606} // namespace v8