blob: 2c8c0925aa37cd5d83d73b8869d8fb74310d1af4 [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
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name,
18 Handle<Map> stub_holder,
19 Code::Kind kind,
Ben Murdochc5610432016-08-08 18:44:38 +010020 CacheHolderFlag cache_holder) {
21 Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder);
22 Code* code = stub_holder->LookupInCodeCache(*name, flags);
23 if (code == nullptr) return Handle<Code>();
24 return handle(code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000025}
26
27
28Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000029 Handle<Name> name, Handle<Map> receiver_map) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030 Isolate* isolate = name->GetIsolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031 if (receiver_map->prototype()->IsNull()) {
32 // TODO(jkummerow/verwaest): If there is no prototype and the property
33 // is nonexistent, introduce a builtin to handle this (fast properties
34 // -> return undefined, dictionary properties -> do negative lookup).
35 return Handle<Code>();
36 }
37 CacheHolderFlag flag;
38 Handle<Map> stub_holder_map =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000039 IC::GetHandlerCacheHolder(receiver_map, false, isolate, &flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040
41 // If no dictionary mode objects are present in the prototype chain, the load
42 // nonexistent IC stub can be shared for all names for a given map and we use
43 // the empty string for the map cache in that case. If there are dictionary
44 // mode objects involved, we need to do negative lookups in the stub and
45 // therefore the stub will be specific to the name.
46 Handle<Name> cache_name =
47 receiver_map->is_dictionary_map()
48 ? name
49 : Handle<Name>::cast(isolate->factory()->nonexistent_symbol());
50 Handle<Map> current_map = stub_holder_map;
51 Handle<JSObject> last(JSObject::cast(receiver_map->prototype()));
52 while (true) {
53 if (current_map->is_dictionary_map()) cache_name = name;
54 if (current_map->prototype()->IsNull()) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000055 if (name->IsPrivate()) {
56 // TODO(verwaest): Use nonexistent_private_symbol.
57 cache_name = name;
Ben Murdoch097c5b22016-05-18 11:27:45 +010058 if (!current_map->has_hidden_prototype()) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000059 }
60
Ben Murdochb8a8cc12014-11-26 15:28:44 +000061 last = handle(JSObject::cast(current_map->prototype()));
62 current_map = handle(last->map());
63 }
64 // Compile the stub that is either shared for all names or
65 // name specific if there are global objects involved.
66 Handle<Code> handler = PropertyHandlerCompiler::Find(
Ben Murdochc5610432016-08-08 18:44:38 +010067 cache_name, stub_holder_map, Code::LOAD_IC, flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000068 if (!handler.is_null()) return handler;
69
Ben Murdochc5610432016-08-08 18:44:38 +010070 TRACE_HANDLER_STATS(isolate, LoadIC_LoadNonexistent);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000071 NamedLoadHandlerCompiler compiler(isolate, receiver_map, last, flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000072 handler = compiler.CompileLoadNonexistent(cache_name);
73 Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
74 return handler;
75}
76
77
78Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000079 Handle<Name> name) {
Ben Murdochc5610432016-08-08 18:44:38 +010080 Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000081 Handle<Code> code = GetCodeWithFlags(flags, name);
Ben Murdochda12d292016-06-02 14:46:10 +010082 PROFILE(isolate(), CodeCreateEvent(Logger::HANDLER_TAG,
83 AbstractCode::cast(*code), *name));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000084#ifdef DEBUG
85 code->VerifyEmbeddedObjects();
86#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087 return code;
88}
89
90
Ben Murdochb8a8cc12014-11-26 15:28:44 +000091#define __ ACCESS_MASM(masm())
92
93
94Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
95 Handle<Name> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000096 Label* miss,
97 ReturnHolder return_what) {
98 PrototypeCheckType check_type = SKIP_RECEIVER;
99 int function_index = map()->IsPrimitiveMap()
100 ? map()->GetConstructorFunctionIndex()
101 : Map::kNoConstructorFunctionIndex;
102 if (function_index != Map::kNoConstructorFunctionIndex) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000103 GenerateDirectLoadGlobalFunctionPrototype(masm(), function_index,
104 scratch1(), miss);
105 Object* function = isolate()->native_context()->get(function_index);
106 Object* prototype = JSFunction::cast(function)->instance_prototype();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000107 Handle<Map> map(JSObject::cast(prototype)->map());
108 set_map(map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000109 object_reg = scratch1();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000110 check_type = CHECK_ALL_MAPS;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000111 }
112
113 // Check that the maps starting from the prototype haven't changed.
114 return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000115 miss, check_type, return_what);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000116}
117
118
119// Frontend for store uses the name register. It has to be restored before a
120// miss.
121Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg,
122 Handle<Name> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000123 Label* miss,
124 ReturnHolder return_what) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125 return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000126 miss, SKIP_RECEIVER, return_what);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000127}
128
129
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400130Register PropertyHandlerCompiler::Frontend(Handle<Name> name) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000131 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400132 if (IC::ICUseVector(kind())) {
133 PushVectorAndSlot();
134 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000135 Register reg = FrontendHeader(receiver(), name, &miss, RETURN_HOLDER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000136 FrontendFooter(name, &miss);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400137 // The footer consumes the vector and slot from the stack if miss occurs.
138 if (IC::ICUseVector(kind())) {
139 DiscardVectorAndSlot();
140 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 return reg;
142}
143
144
145void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name,
146 Label* miss,
147 Register scratch1,
148 Register scratch2) {
149 Register holder_reg;
150 Handle<Map> last_map;
151 if (holder().is_null()) {
152 holder_reg = receiver();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000153 last_map = map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000154 // If |type| has null as its prototype, |holder()| is
155 // Handle<JSObject>::null().
156 DCHECK(last_map->prototype() == isolate()->heap()->null_value());
157 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000158 last_map = handle(holder()->map());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000159 // This condition matches the branches below.
160 bool need_holder =
161 last_map->is_dictionary_map() && !last_map->IsJSGlobalObjectMap();
162 holder_reg =
163 FrontendHeader(receiver(), name, miss,
164 need_holder ? RETURN_HOLDER : DONT_RETURN_ANYTHING);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000165 }
166
167 if (last_map->is_dictionary_map()) {
168 if (last_map->IsJSGlobalObjectMap()) {
169 Handle<JSGlobalObject> global =
170 holder().is_null()
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000171 ? Handle<JSGlobalObject>::cast(isolate()->global_object())
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000172 : Handle<JSGlobalObject>::cast(holder());
173 GenerateCheckPropertyCell(masm(), global, name, scratch1, miss);
174 } else {
175 if (!name->IsUniqueName()) {
176 DCHECK(name->IsString());
177 name = factory()->InternalizeString(Handle<String>::cast(name));
178 }
179 DCHECK(holder().is_null() ||
180 holder()->property_dictionary()->FindEntry(name) ==
181 NameDictionary::kNotFound);
182 GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1,
183 scratch2);
184 }
185 }
186}
187
188
189Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name,
190 FieldIndex field) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400191 Register reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000192 __ Move(receiver(), reg);
193 LoadFieldStub stub(isolate(), field);
194 GenerateTailCall(masm(), stub.GetCode());
Ben Murdochc5610432016-08-08 18:44:38 +0100195 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000196}
197
198
199Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name,
200 int constant_index) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400201 Register reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000202 __ Move(receiver(), reg);
203 LoadConstantStub stub(isolate(), constant_index);
204 GenerateTailCall(masm(), stub.GetCode());
Ben Murdochc5610432016-08-08 18:44:38 +0100205 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000206}
207
208
209Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
210 Handle<Name> name) {
211 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400212 if (IC::ICUseVector(kind())) {
213 DCHECK(kind() == Code::LOAD_IC);
214 PushVectorAndSlot();
215 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000216 NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400217 if (IC::ICUseVector(kind())) {
218 DiscardVectorAndSlot();
219 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000220 GenerateLoadConstant(isolate()->factory()->undefined_value());
221 FrontendFooter(name, &miss);
Ben Murdochc5610432016-08-08 18:44:38 +0100222 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223}
224
225
226Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100227 Handle<Name> name, Handle<AccessorInfo> callback) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400228 Register reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000229 GenerateLoadCallback(reg, callback);
Ben Murdochc5610432016-08-08 18:44:38 +0100230 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000231}
232
233
234Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000235 Handle<Name> name, const CallOptimization& call_optimization,
236 int accessor_index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000237 DCHECK(call_optimization.is_simple_api_call());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000238 Register holder = Frontend(name);
239 GenerateApiAccessorCall(masm(), call_optimization, map(), receiver(),
240 scratch2(), false, no_reg, holder, accessor_index);
Ben Murdochc5610432016-08-08 18:44:38 +0100241 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000242}
243
244
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400245void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) {
246 if (IC::ICUseVector(kind())) {
247 if (holder_reg.is(receiver())) {
248 PushVectorAndSlot();
249 } else {
250 DCHECK(holder_reg.is(scratch1()));
251 PushVectorAndSlot(scratch2(), scratch3());
252 }
253 }
254}
255
256
257void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg,
258 PopMode mode) {
259 if (IC::ICUseVector(kind())) {
260 if (mode == DISCARD) {
261 DiscardVectorAndSlot();
262 } else {
263 if (holder_reg.is(receiver())) {
264 PopVectorAndSlot();
265 } else {
266 DCHECK(holder_reg.is(scratch1()));
267 PopVectorAndSlot(scratch2(), scratch3());
268 }
269 }
270 }
271}
272
273
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000274Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
275 LookupIterator* it) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000276 // So far the most popular follow ups for interceptor loads are DATA and
Ben Murdoch097c5b22016-05-18 11:27:45 +0100277 // AccessorInfo, so inline only them. Other cases may be added
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000278 // later.
279 bool inline_followup = false;
280 switch (it->state()) {
281 case LookupIterator::TRANSITION:
282 UNREACHABLE();
283 case LookupIterator::ACCESS_CHECK:
284 case LookupIterator::INTERCEPTOR:
285 case LookupIterator::JSPROXY:
286 case LookupIterator::NOT_FOUND:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000288 break;
289 case LookupIterator::DATA:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400290 inline_followup =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000291 it->property_details().type() == DATA && !it->is_dictionary_holder();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000292 break;
293 case LookupIterator::ACCESSOR: {
294 Handle<Object> accessors = it->GetAccessors();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100295 if (accessors->IsAccessorInfo()) {
296 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
297 inline_followup =
298 info->getter() != NULL &&
299 AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000300 } else if (accessors->IsAccessorPair()) {
301 Handle<JSObject> property_holder(it->GetHolder<JSObject>());
302 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
303 isolate());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100304 if (!(getter->IsJSFunction() || getter->IsFunctionTemplateInfo())) {
305 break;
306 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000307 if (!property_holder->HasFastProperties()) break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100308 CallOptimization call_optimization(getter);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000309 Handle<Map> receiver_map = map();
310 inline_followup = call_optimization.is_simple_api_call() &&
311 call_optimization.IsCompatibleReceiverMap(
312 receiver_map, property_holder);
313 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000314 }
315 }
316
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400317 Label miss;
318 InterceptorVectorSlotPush(receiver());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000319 bool lost_holder_register = false;
320 auto holder_orig = holder();
321 // non masking interceptors must check the entire chain, so temporarily reset
322 // the holder to be that last element for the FrontendHeader call.
323 if (holder()->GetNamedInterceptor()->non_masking()) {
324 DCHECK(!inline_followup);
325 JSObject* last = *holder();
326 PrototypeIterator iter(isolate(), last);
327 while (!iter.IsAtEnd()) {
328 lost_holder_register = true;
329 // Casting to JSObject is fine here. The LookupIterator makes sure to
330 // look behind non-masking interceptors during the original lookup, and
331 // we wouldn't try to compile a handler if there was a Proxy anywhere.
332 last = iter.GetCurrent<JSObject>();
333 iter.Advance();
334 }
335 auto last_handle = handle(last);
336 set_holder(last_handle);
337 }
338 Register reg = FrontendHeader(receiver(), it->name(), &miss, RETURN_HOLDER);
339 // Reset the holder so further calculations are correct.
340 set_holder(holder_orig);
341 if (lost_holder_register) {
342 if (*it->GetReceiver() == *holder()) {
343 reg = receiver();
344 } else {
345 // Reload lost holder register.
346 auto cell = isolate()->factory()->NewWeakCell(holder());
347 __ LoadWeakValue(reg, cell, &miss);
348 }
349 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400350 FrontendFooter(it->name(), &miss);
351 InterceptorVectorSlotPop(reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000352 if (inline_followup) {
353 // TODO(368): Compile in the whole chain: all the interceptors in
354 // prototypes and ultimate answer.
355 GenerateLoadInterceptorWithFollowup(it, reg);
356 } else {
357 GenerateLoadInterceptor(reg);
358 }
Ben Murdochc5610432016-08-08 18:44:38 +0100359 return GetCode(kind(), it->name());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000360}
361
Ben Murdochc5610432016-08-08 18:44:38 +0100362void NamedLoadHandlerCompiler::GenerateLoadCallback(
363 Register reg, Handle<AccessorInfo> callback) {
364 DCHECK(receiver().is(ApiGetterDescriptor::ReceiverRegister()));
365 __ Move(ApiGetterDescriptor::HolderRegister(), reg);
366 // The callback is alive if this instruction is executed,
367 // so the weak cell is not cleared and points to data.
368 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
369 __ GetWeakValue(ApiGetterDescriptor::CallbackRegister(), cell);
370
371 CallApiGetterStub stub(isolate());
372 __ TailCallStub(&stub);
373}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000374
375void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
376 LookupIterator* it, Register interceptor_reg) {
377 Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>());
378
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000379 Handle<Map> holder_map(holder()->map());
380 set_map(holder_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000381 set_holder(real_named_property_holder);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400382
383 Label miss;
384 InterceptorVectorSlotPush(interceptor_reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000385 Register reg =
386 FrontendHeader(interceptor_reg, it->name(), &miss, RETURN_HOLDER);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400387 FrontendFooter(it->name(), &miss);
388 // We discard the vector and slot now because we don't miss below this point.
389 InterceptorVectorSlotPop(reg, DISCARD);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000390
391 switch (it->state()) {
392 case LookupIterator::ACCESS_CHECK:
393 case LookupIterator::INTERCEPTOR:
394 case LookupIterator::JSPROXY:
395 case LookupIterator::NOT_FOUND:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000396 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000397 case LookupIterator::TRANSITION:
398 UNREACHABLE();
399 case LookupIterator::DATA: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000400 DCHECK_EQ(DATA, it->property_details().type());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000401 __ Move(receiver(), reg);
402 LoadFieldStub stub(isolate(), it->GetFieldIndex());
403 GenerateTailCall(masm(), stub.GetCode());
404 break;
405 }
406 case LookupIterator::ACCESSOR:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100407 if (it->GetAccessors()->IsAccessorInfo()) {
408 Handle<AccessorInfo> info =
409 Handle<AccessorInfo>::cast(it->GetAccessors());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000410 DCHECK_NOT_NULL(info->getter());
411 GenerateLoadCallback(reg, info);
412 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100413 Handle<Object> function = handle(
414 AccessorPair::cast(*it->GetAccessors())->getter(), isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415 CallOptimization call_optimization(function);
416 GenerateApiAccessorCall(masm(), call_optimization, holder_map,
417 receiver(), scratch2(), false, no_reg, reg,
418 it->GetAccessorIndex());
419 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000420 }
421}
422
423
424Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000425 Handle<Name> name, int accessor_index, int expected_arguments) {
426 Register holder = Frontend(name);
427 GenerateLoadViaGetter(masm(), map(), receiver(), holder, accessor_index,
428 expected_arguments, scratch2());
Ben Murdochc5610432016-08-08 18:44:38 +0100429 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000430}
431
432
433// TODO(verwaest): Cleanup. holder() is actually the receiver.
434Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
435 Handle<Map> transition, Handle<Name> name) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400436 Label miss;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000437
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000438 PushVectorAndSlot();
439
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000440 // Check that we are allowed to write this.
441 bool is_nonexistent = holder()->map() == transition->GetBackPointer();
442 if (is_nonexistent) {
443 // Find the top object.
444 Handle<JSObject> last;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000445 PrototypeIterator::WhereToEnd end =
446 name->IsPrivate() ? PrototypeIterator::END_AT_NON_HIDDEN
447 : PrototypeIterator::END_AT_NULL;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100448 PrototypeIterator iter(isolate(), holder(),
449 PrototypeIterator::START_AT_PROTOTYPE, end);
450 while (!iter.IsAtEnd()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000451 last = PrototypeIterator::GetCurrent<JSObject>(iter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000452 iter.Advance();
453 }
454 if (!last.is_null()) set_holder(last);
455 NonexistentFrontendHeader(name, &miss, scratch1(), scratch2());
456 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000457 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000458 DCHECK(holder()->HasFastProperties());
459 }
460
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400461 int descriptor = transition->LastAdded();
462 Handle<DescriptorArray> descriptors(transition->instance_descriptors());
463 PropertyDetails details = descriptors->GetDetails(descriptor);
464 Representation representation = details.representation();
465 DCHECK(!representation.IsNone());
466
467 // Stub is never generated for objects that require access checks.
468 DCHECK(!transition->is_access_check_needed());
469
470 // Call to respective StoreTransitionStub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000471 bool virtual_args = StoreTransitionHelper::HasVirtualSlotArg();
472 Register map_reg = StoreTransitionHelper::MapRegister();
473
474 if (details.type() == DATA_CONSTANT) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400475 DCHECK(descriptors->GetValue(descriptor)->IsJSFunction());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000476 Register tmp =
477 virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
478 GenerateRestoreMap(transition, tmp, scratch2(), &miss);
479 GenerateConstantCheck(tmp, descriptor, value(), scratch2(), &miss);
480 if (virtual_args) {
481 // This will move the map from tmp into map_reg.
482 RearrangeVectorAndSlot(tmp, map_reg);
483 } else {
484 PopVectorAndSlot();
485 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400486 GenerateRestoreName(name);
487 StoreTransitionStub stub(isolate());
488 GenerateTailCall(masm(), stub.GetCode());
489
490 } else {
491 if (representation.IsHeapObject()) {
492 GenerateFieldTypeChecks(descriptors->GetFieldType(descriptor), value(),
493 &miss);
494 }
495 StoreTransitionStub::StoreMode store_mode =
496 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0
497 ? StoreTransitionStub::ExtendStorageAndStoreMapAndValue
498 : StoreTransitionStub::StoreMapAndValue;
499
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000500 Register tmp =
501 virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
502 GenerateRestoreMap(transition, tmp, scratch2(), &miss);
503 if (virtual_args) {
504 RearrangeVectorAndSlot(tmp, map_reg);
505 } else {
506 PopVectorAndSlot();
507 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400508 GenerateRestoreName(name);
509 StoreTransitionStub stub(isolate(),
510 FieldIndex::ForDescriptor(*transition, descriptor),
511 representation, store_mode);
512 GenerateTailCall(masm(), stub.GetCode());
513 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000514
515 GenerateRestoreName(&miss, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000516 PopVectorAndSlot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000517 TailCallBuiltin(masm(), MissBuiltin(kind()));
518
Ben Murdochc5610432016-08-08 18:44:38 +0100519 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000520}
521
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000522bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100523 FieldType* field_type) const {
524 return field_type->IsClass();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000525}
526
527
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000528Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) {
529 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400530 DCHECK(it->representation().IsHeapObject());
531
Ben Murdoch097c5b22016-05-18 11:27:45 +0100532 FieldType* field_type = *it->GetFieldType();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000533 bool need_save_restore = false;
534 if (RequiresFieldTypeChecks(field_type)) {
535 need_save_restore = IC::ICUseVector(kind());
536 if (need_save_restore) PushVectorAndSlot();
537 GenerateFieldTypeChecks(field_type, value(), &miss);
538 if (need_save_restore) PopVectorAndSlot();
539 }
540
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400541 StoreFieldStub stub(isolate(), it->GetFieldIndex(), it->representation());
542 GenerateTailCall(masm(), stub.GetCode());
543
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000544 __ bind(&miss);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000545 if (need_save_restore) PopVectorAndSlot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000546 TailCallBuiltin(masm(), MissBuiltin(kind()));
Ben Murdochc5610432016-08-08 18:44:38 +0100547 return GetCode(kind(), it->name());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000548}
549
550
551Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000552 Handle<JSObject> object, Handle<Name> name, int accessor_index,
553 int expected_arguments) {
554 Register holder = Frontend(name);
555 GenerateStoreViaSetter(masm(), map(), receiver(), holder, accessor_index,
556 expected_arguments, scratch2());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000557
Ben Murdochc5610432016-08-08 18:44:38 +0100558 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000559}
560
561
562Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
563 Handle<JSObject> object, Handle<Name> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000564 const CallOptimization& call_optimization, int accessor_index) {
565 Register holder = Frontend(name);
566 GenerateApiAccessorCall(masm(), call_optimization, handle(object->map()),
567 receiver(), scratch2(), true, value(), holder,
568 accessor_index);
Ben Murdochc5610432016-08-08 18:44:38 +0100569 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000570}
571
572
573#undef __
574
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575void ElementHandlerCompiler::CompileElementHandlers(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100576 MapHandleList* receiver_maps, CodeHandleList* handlers) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000577 for (int i = 0; i < receiver_maps->length(); ++i) {
578 Handle<Map> receiver_map = receiver_maps->at(i);
579 Handle<Code> cached_stub;
580
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400581 if (receiver_map->IsStringMap()) {
582 cached_stub = LoadIndexedStringStub(isolate()).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000583 } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100584 cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000585 } else {
586 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
587 ElementsKind elements_kind = receiver_map->elements_kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000588
589 // No need to check for an elements-free prototype chain here, the
590 // generated stub code needs to check that dynamically anyway.
591 bool convert_hole_to_undefined =
592 (is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
Ben Murdoch097c5b22016-05-18 11:27:45 +0100593 *receiver_map == isolate()->get_initial_js_array_map(elements_kind));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000594
Ben Murdochda12d292016-06-02 14:46:10 +0100595 if (receiver_map->has_indexed_interceptor() &&
596 !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined() &&
597 !receiver_map->GetIndexedInterceptor()->non_masking()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000598 cached_stub = LoadIndexedInterceptorStub(isolate()).GetCode();
599 } else if (IsSloppyArgumentsElements(elements_kind)) {
600 cached_stub = KeyedLoadSloppyArgumentsStub(isolate()).GetCode();
601 } else if (IsFastElementsKind(elements_kind) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000602 IsFixedTypedArrayElementsKind(elements_kind)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000603 cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind,
604 convert_hole_to_undefined).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000605 } else {
606 DCHECK(elements_kind == DICTIONARY_ELEMENTS);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100607 LoadICState state = LoadICState(kNoExtraICState);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000608 cached_stub = LoadDictionaryElementStub(isolate(), state).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000609 }
610 }
611
612 handlers->Add(cached_stub);
613 }
614}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000615} // namespace internal
616} // namespace v8