blob: 6d153bbc256bd02df331e9c9541c961f375764f3 [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"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012
13namespace v8 {
14namespace internal {
15
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name,
17 Handle<Map> stub_holder,
18 Code::Kind kind,
Ben Murdochc5610432016-08-08 18:44:38 +010019 CacheHolderFlag cache_holder) {
20 Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder);
21 Code* code = stub_holder->LookupInCodeCache(*name, flags);
22 if (code == nullptr) return Handle<Code>();
23 return handle(code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024}
25
26
27Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028 Handle<Name> name, Handle<Map> receiver_map) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000029 Isolate* isolate = name->GetIsolate();
Ben Murdoch61f157c2016-09-16 13:49:30 +010030 if (receiver_map->prototype()->IsNull(isolate)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031 // TODO(jkummerow/verwaest): If there is no prototype and the property
32 // is nonexistent, introduce a builtin to handle this (fast properties
33 // -> return undefined, dictionary properties -> do negative lookup).
34 return Handle<Code>();
35 }
36 CacheHolderFlag flag;
37 Handle<Map> stub_holder_map =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000038 IC::GetHandlerCacheHolder(receiver_map, false, isolate, &flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000039
40 // If no dictionary mode objects are present in the prototype chain, the load
41 // nonexistent IC stub can be shared for all names for a given map and we use
42 // the empty string for the map cache in that case. If there are dictionary
43 // mode objects involved, we need to do negative lookups in the stub and
44 // therefore the stub will be specific to the name.
45 Handle<Name> cache_name =
46 receiver_map->is_dictionary_map()
47 ? name
48 : Handle<Name>::cast(isolate->factory()->nonexistent_symbol());
49 Handle<Map> current_map = stub_holder_map;
50 Handle<JSObject> last(JSObject::cast(receiver_map->prototype()));
51 while (true) {
52 if (current_map->is_dictionary_map()) cache_name = name;
Ben Murdoch61f157c2016-09-16 13:49:30 +010053 if (current_map->prototype()->IsNull(isolate)) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000054 if (name->IsPrivate()) {
55 // TODO(verwaest): Use nonexistent_private_symbol.
56 cache_name = name;
Ben Murdoch097c5b22016-05-18 11:27:45 +010057 if (!current_map->has_hidden_prototype()) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000058 }
59
Ben Murdochb8a8cc12014-11-26 15:28:44 +000060 last = handle(JSObject::cast(current_map->prototype()));
61 current_map = handle(last->map());
62 }
63 // Compile the stub that is either shared for all names or
64 // name specific if there are global objects involved.
65 Handle<Code> handler = PropertyHandlerCompiler::Find(
Ben Murdochc5610432016-08-08 18:44:38 +010066 cache_name, stub_holder_map, Code::LOAD_IC, flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000067 if (!handler.is_null()) return handler;
68
Ben Murdochc5610432016-08-08 18:44:38 +010069 TRACE_HANDLER_STATS(isolate, LoadIC_LoadNonexistent);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000070 NamedLoadHandlerCompiler compiler(isolate, receiver_map, last, flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000071 handler = compiler.CompileLoadNonexistent(cache_name);
72 Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
73 return handler;
74}
75
76
77Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000078 Handle<Name> name) {
Ben Murdochc5610432016-08-08 18:44:38 +010079 Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000080 Handle<Code> code = GetCodeWithFlags(flags, name);
Ben Murdoch61f157c2016-09-16 13:49:30 +010081 PROFILE(isolate(), CodeCreateEvent(CodeEventListener::HANDLER_TAG,
Ben Murdochda12d292016-06-02 14:46:10 +010082 AbstractCode::cast(*code), *name));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000083#ifdef DEBUG
84 code->VerifyEmbeddedObjects();
85#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000086 return code;
87}
88
89
Ben Murdochb8a8cc12014-11-26 15:28:44 +000090#define __ ACCESS_MASM(masm())
91
92
93Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
94 Handle<Name> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000095 Label* miss,
96 ReturnHolder return_what) {
97 PrototypeCheckType check_type = SKIP_RECEIVER;
98 int function_index = map()->IsPrimitiveMap()
99 ? map()->GetConstructorFunctionIndex()
100 : Map::kNoConstructorFunctionIndex;
101 if (function_index != Map::kNoConstructorFunctionIndex) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000102 GenerateDirectLoadGlobalFunctionPrototype(masm(), function_index,
103 scratch1(), miss);
104 Object* function = isolate()->native_context()->get(function_index);
105 Object* prototype = JSFunction::cast(function)->instance_prototype();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000106 Handle<Map> map(JSObject::cast(prototype)->map());
107 set_map(map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000108 object_reg = scratch1();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000109 check_type = CHECK_ALL_MAPS;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000110 }
111
112 // Check that the maps starting from the prototype haven't changed.
113 return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000114 miss, check_type, return_what);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000115}
116
117
118// Frontend for store uses the name register. It has to be restored before a
119// miss.
120Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg,
121 Handle<Name> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000122 Label* miss,
123 ReturnHolder return_what) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000124 return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000125 miss, SKIP_RECEIVER, return_what);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000126}
127
128
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400129Register PropertyHandlerCompiler::Frontend(Handle<Name> name) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400131 if (IC::ICUseVector(kind())) {
132 PushVectorAndSlot();
133 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000134 Register reg = FrontendHeader(receiver(), name, &miss, RETURN_HOLDER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000135 FrontendFooter(name, &miss);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400136 // The footer consumes the vector and slot from the stack if miss occurs.
137 if (IC::ICUseVector(kind())) {
138 DiscardVectorAndSlot();
139 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000140 return reg;
141}
142
143
144void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name,
145 Label* miss,
146 Register scratch1,
147 Register scratch2) {
148 Register holder_reg;
149 Handle<Map> last_map;
150 if (holder().is_null()) {
151 holder_reg = receiver();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152 last_map = map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000153 // If |type| has null as its prototype, |holder()| is
154 // Handle<JSObject>::null().
155 DCHECK(last_map->prototype() == isolate()->heap()->null_value());
156 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000157 last_map = handle(holder()->map());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000158 // This condition matches the branches below.
159 bool need_holder =
160 last_map->is_dictionary_map() && !last_map->IsJSGlobalObjectMap();
161 holder_reg =
162 FrontendHeader(receiver(), name, miss,
163 need_holder ? RETURN_HOLDER : DONT_RETURN_ANYTHING);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000164 }
165
166 if (last_map->is_dictionary_map()) {
167 if (last_map->IsJSGlobalObjectMap()) {
168 Handle<JSGlobalObject> global =
169 holder().is_null()
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000170 ? Handle<JSGlobalObject>::cast(isolate()->global_object())
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171 : Handle<JSGlobalObject>::cast(holder());
172 GenerateCheckPropertyCell(masm(), global, name, scratch1, miss);
173 } else {
174 if (!name->IsUniqueName()) {
175 DCHECK(name->IsString());
176 name = factory()->InternalizeString(Handle<String>::cast(name));
177 }
178 DCHECK(holder().is_null() ||
179 holder()->property_dictionary()->FindEntry(name) ==
180 NameDictionary::kNotFound);
181 GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1,
182 scratch2);
183 }
184 }
185}
186
187
188Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name,
189 FieldIndex field) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400190 Register reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000191 __ Move(receiver(), reg);
192 LoadFieldStub stub(isolate(), field);
193 GenerateTailCall(masm(), stub.GetCode());
Ben Murdochc5610432016-08-08 18:44:38 +0100194 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000195}
196
197
198Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name,
199 int constant_index) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400200 Register reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201 __ Move(receiver(), reg);
202 LoadConstantStub stub(isolate(), constant_index);
203 GenerateTailCall(masm(), stub.GetCode());
Ben Murdochc5610432016-08-08 18:44:38 +0100204 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000205}
206
207
208Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
209 Handle<Name> name) {
210 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400211 if (IC::ICUseVector(kind())) {
212 DCHECK(kind() == Code::LOAD_IC);
213 PushVectorAndSlot();
214 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000215 NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400216 if (IC::ICUseVector(kind())) {
217 DiscardVectorAndSlot();
218 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219 GenerateLoadConstant(isolate()->factory()->undefined_value());
220 FrontendFooter(name, &miss);
Ben Murdochc5610432016-08-08 18:44:38 +0100221 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000222}
223
224
225Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100226 Handle<Name> name, Handle<AccessorInfo> callback) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400227 Register reg = Frontend(name);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100228 if (FLAG_runtime_call_stats) {
229 TailCallBuiltin(masm(), Builtins::kLoadIC_Slow);
230 } else {
231 GenerateLoadCallback(reg, callback);
232 }
Ben Murdochc5610432016-08-08 18:44:38 +0100233 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000234}
235
236
237Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000238 Handle<Name> name, const CallOptimization& call_optimization,
239 int accessor_index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000240 DCHECK(call_optimization.is_simple_api_call());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000241 Register holder = Frontend(name);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100242 if (FLAG_runtime_call_stats) {
243 TailCallBuiltin(masm(), Builtins::kLoadIC_Slow);
244 } else {
245 GenerateApiAccessorCall(masm(), call_optimization, map(), receiver(),
246 scratch2(), false, no_reg, holder, accessor_index);
247 }
Ben Murdochc5610432016-08-08 18:44:38 +0100248 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000249}
250
251
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400252void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) {
253 if (IC::ICUseVector(kind())) {
254 if (holder_reg.is(receiver())) {
255 PushVectorAndSlot();
256 } else {
257 DCHECK(holder_reg.is(scratch1()));
258 PushVectorAndSlot(scratch2(), scratch3());
259 }
260 }
261}
262
263
264void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg,
265 PopMode mode) {
266 if (IC::ICUseVector(kind())) {
267 if (mode == DISCARD) {
268 DiscardVectorAndSlot();
269 } else {
270 if (holder_reg.is(receiver())) {
271 PopVectorAndSlot();
272 } else {
273 DCHECK(holder_reg.is(scratch1()));
274 PopVectorAndSlot(scratch2(), scratch3());
275 }
276 }
277 }
278}
279
280
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000281Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
282 LookupIterator* it) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000283 // So far the most popular follow ups for interceptor loads are DATA and
Ben Murdoch097c5b22016-05-18 11:27:45 +0100284 // AccessorInfo, so inline only them. Other cases may be added
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000285 // later.
286 bool inline_followup = false;
287 switch (it->state()) {
288 case LookupIterator::TRANSITION:
289 UNREACHABLE();
290 case LookupIterator::ACCESS_CHECK:
291 case LookupIterator::INTERCEPTOR:
292 case LookupIterator::JSPROXY:
293 case LookupIterator::NOT_FOUND:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000294 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 break;
296 case LookupIterator::DATA:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400297 inline_followup =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000298 it->property_details().type() == DATA && !it->is_dictionary_holder();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299 break;
300 case LookupIterator::ACCESSOR: {
301 Handle<Object> accessors = it->GetAccessors();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100302 if (accessors->IsAccessorInfo()) {
303 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
304 inline_followup =
305 info->getter() != NULL &&
306 AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000307 } else if (accessors->IsAccessorPair()) {
308 Handle<JSObject> property_holder(it->GetHolder<JSObject>());
309 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
310 isolate());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100311 if (!(getter->IsJSFunction() || getter->IsFunctionTemplateInfo())) {
312 break;
313 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000314 if (!property_holder->HasFastProperties()) break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100315 CallOptimization call_optimization(getter);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000316 Handle<Map> receiver_map = map();
317 inline_followup = call_optimization.is_simple_api_call() &&
318 call_optimization.IsCompatibleReceiverMap(
319 receiver_map, property_holder);
320 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000321 }
322 }
323
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400324 Label miss;
325 InterceptorVectorSlotPush(receiver());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000326 bool lost_holder_register = false;
327 auto holder_orig = holder();
328 // non masking interceptors must check the entire chain, so temporarily reset
329 // the holder to be that last element for the FrontendHeader call.
330 if (holder()->GetNamedInterceptor()->non_masking()) {
331 DCHECK(!inline_followup);
332 JSObject* last = *holder();
333 PrototypeIterator iter(isolate(), last);
334 while (!iter.IsAtEnd()) {
335 lost_holder_register = true;
336 // Casting to JSObject is fine here. The LookupIterator makes sure to
337 // look behind non-masking interceptors during the original lookup, and
338 // we wouldn't try to compile a handler if there was a Proxy anywhere.
339 last = iter.GetCurrent<JSObject>();
340 iter.Advance();
341 }
342 auto last_handle = handle(last);
343 set_holder(last_handle);
344 }
345 Register reg = FrontendHeader(receiver(), it->name(), &miss, RETURN_HOLDER);
346 // Reset the holder so further calculations are correct.
347 set_holder(holder_orig);
348 if (lost_holder_register) {
349 if (*it->GetReceiver() == *holder()) {
350 reg = receiver();
351 } else {
352 // Reload lost holder register.
353 auto cell = isolate()->factory()->NewWeakCell(holder());
354 __ LoadWeakValue(reg, cell, &miss);
355 }
356 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400357 FrontendFooter(it->name(), &miss);
358 InterceptorVectorSlotPop(reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000359 if (inline_followup) {
360 // TODO(368): Compile in the whole chain: all the interceptors in
361 // prototypes and ultimate answer.
362 GenerateLoadInterceptorWithFollowup(it, reg);
363 } else {
364 GenerateLoadInterceptor(reg);
365 }
Ben Murdochc5610432016-08-08 18:44:38 +0100366 return GetCode(kind(), it->name());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000367}
368
Ben Murdochc5610432016-08-08 18:44:38 +0100369void NamedLoadHandlerCompiler::GenerateLoadCallback(
370 Register reg, Handle<AccessorInfo> callback) {
371 DCHECK(receiver().is(ApiGetterDescriptor::ReceiverRegister()));
372 __ Move(ApiGetterDescriptor::HolderRegister(), reg);
373 // The callback is alive if this instruction is executed,
374 // so the weak cell is not cleared and points to data.
375 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
376 __ GetWeakValue(ApiGetterDescriptor::CallbackRegister(), cell);
377
378 CallApiGetterStub stub(isolate());
379 __ TailCallStub(&stub);
380}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000381
382void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
383 LookupIterator* it, Register interceptor_reg) {
384 Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>());
385
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000386 Handle<Map> holder_map(holder()->map());
387 set_map(holder_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000388 set_holder(real_named_property_holder);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400389
390 Label miss;
391 InterceptorVectorSlotPush(interceptor_reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000392 Register reg =
393 FrontendHeader(interceptor_reg, it->name(), &miss, RETURN_HOLDER);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400394 FrontendFooter(it->name(), &miss);
395 // We discard the vector and slot now because we don't miss below this point.
396 InterceptorVectorSlotPop(reg, DISCARD);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000397
398 switch (it->state()) {
399 case LookupIterator::ACCESS_CHECK:
400 case LookupIterator::INTERCEPTOR:
401 case LookupIterator::JSPROXY:
402 case LookupIterator::NOT_FOUND:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000403 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000404 case LookupIterator::TRANSITION:
405 UNREACHABLE();
406 case LookupIterator::DATA: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000407 DCHECK_EQ(DATA, it->property_details().type());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000408 __ Move(receiver(), reg);
409 LoadFieldStub stub(isolate(), it->GetFieldIndex());
410 GenerateTailCall(masm(), stub.GetCode());
411 break;
412 }
413 case LookupIterator::ACCESSOR:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100414 if (it->GetAccessors()->IsAccessorInfo()) {
415 Handle<AccessorInfo> info =
416 Handle<AccessorInfo>::cast(it->GetAccessors());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000417 DCHECK_NOT_NULL(info->getter());
418 GenerateLoadCallback(reg, info);
419 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100420 Handle<Object> function = handle(
421 AccessorPair::cast(*it->GetAccessors())->getter(), isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000422 CallOptimization call_optimization(function);
423 GenerateApiAccessorCall(masm(), call_optimization, holder_map,
424 receiver(), scratch2(), false, no_reg, reg,
425 it->GetAccessorIndex());
426 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000427 }
428}
429
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000430Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000431 Handle<Name> name, int accessor_index, int expected_arguments) {
432 Register holder = Frontend(name);
433 GenerateLoadViaGetter(masm(), map(), receiver(), holder, accessor_index,
434 expected_arguments, scratch2());
Ben Murdochc5610432016-08-08 18:44:38 +0100435 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000436}
437
438
439// TODO(verwaest): Cleanup. holder() is actually the receiver.
440Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
441 Handle<Map> transition, Handle<Name> name) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400442 Label miss;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000443
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000444 PushVectorAndSlot();
445
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000446 // Check that we are allowed to write this.
447 bool is_nonexistent = holder()->map() == transition->GetBackPointer();
448 if (is_nonexistent) {
449 // Find the top object.
450 Handle<JSObject> last;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000451 PrototypeIterator::WhereToEnd end =
452 name->IsPrivate() ? PrototypeIterator::END_AT_NON_HIDDEN
453 : PrototypeIterator::END_AT_NULL;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100454 PrototypeIterator iter(isolate(), holder(), kStartAtPrototype, end);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100455 while (!iter.IsAtEnd()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000456 last = PrototypeIterator::GetCurrent<JSObject>(iter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000457 iter.Advance();
458 }
459 if (!last.is_null()) set_holder(last);
460 NonexistentFrontendHeader(name, &miss, scratch1(), scratch2());
461 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000462 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000463 DCHECK(holder()->HasFastProperties());
464 }
465
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400466 int descriptor = transition->LastAdded();
467 Handle<DescriptorArray> descriptors(transition->instance_descriptors());
468 PropertyDetails details = descriptors->GetDetails(descriptor);
469 Representation representation = details.representation();
470 DCHECK(!representation.IsNone());
471
472 // Stub is never generated for objects that require access checks.
473 DCHECK(!transition->is_access_check_needed());
474
475 // Call to respective StoreTransitionStub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000476 bool virtual_args = StoreTransitionHelper::HasVirtualSlotArg();
477 Register map_reg = StoreTransitionHelper::MapRegister();
478
479 if (details.type() == DATA_CONSTANT) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400480 DCHECK(descriptors->GetValue(descriptor)->IsJSFunction());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000481 Register tmp =
482 virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
483 GenerateRestoreMap(transition, tmp, scratch2(), &miss);
484 GenerateConstantCheck(tmp, descriptor, value(), scratch2(), &miss);
485 if (virtual_args) {
486 // This will move the map from tmp into map_reg.
487 RearrangeVectorAndSlot(tmp, map_reg);
488 } else {
489 PopVectorAndSlot();
490 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400491 GenerateRestoreName(name);
492 StoreTransitionStub stub(isolate());
493 GenerateTailCall(masm(), stub.GetCode());
494
495 } else {
496 if (representation.IsHeapObject()) {
497 GenerateFieldTypeChecks(descriptors->GetFieldType(descriptor), value(),
498 &miss);
499 }
500 StoreTransitionStub::StoreMode store_mode =
501 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0
502 ? StoreTransitionStub::ExtendStorageAndStoreMapAndValue
503 : StoreTransitionStub::StoreMapAndValue;
504
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000505 Register tmp =
506 virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
507 GenerateRestoreMap(transition, tmp, scratch2(), &miss);
508 if (virtual_args) {
509 RearrangeVectorAndSlot(tmp, map_reg);
510 } else {
511 PopVectorAndSlot();
512 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400513 GenerateRestoreName(name);
514 StoreTransitionStub stub(isolate(),
515 FieldIndex::ForDescriptor(*transition, descriptor),
516 representation, store_mode);
517 GenerateTailCall(masm(), stub.GetCode());
518 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000519
520 GenerateRestoreName(&miss, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000521 PopVectorAndSlot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000522 TailCallBuiltin(masm(), MissBuiltin(kind()));
523
Ben Murdochc5610432016-08-08 18:44:38 +0100524 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000525}
526
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000527bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100528 FieldType* field_type) const {
529 return field_type->IsClass();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000530}
531
532
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000533Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) {
534 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400535 DCHECK(it->representation().IsHeapObject());
536
Ben Murdoch097c5b22016-05-18 11:27:45 +0100537 FieldType* field_type = *it->GetFieldType();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000538 bool need_save_restore = false;
539 if (RequiresFieldTypeChecks(field_type)) {
540 need_save_restore = IC::ICUseVector(kind());
541 if (need_save_restore) PushVectorAndSlot();
542 GenerateFieldTypeChecks(field_type, value(), &miss);
543 if (need_save_restore) PopVectorAndSlot();
544 }
545
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400546 StoreFieldStub stub(isolate(), it->GetFieldIndex(), it->representation());
547 GenerateTailCall(masm(), stub.GetCode());
548
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000549 __ bind(&miss);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000550 if (need_save_restore) PopVectorAndSlot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000551 TailCallBuiltin(masm(), MissBuiltin(kind()));
Ben Murdochc5610432016-08-08 18:44:38 +0100552 return GetCode(kind(), it->name());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000553}
554
555
556Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000557 Handle<JSObject> object, Handle<Name> name, int accessor_index,
558 int expected_arguments) {
559 Register holder = Frontend(name);
560 GenerateStoreViaSetter(masm(), map(), receiver(), holder, accessor_index,
561 expected_arguments, scratch2());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000562
Ben Murdochc5610432016-08-08 18:44:38 +0100563 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000564}
565
566
567Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
568 Handle<JSObject> object, Handle<Name> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000569 const CallOptimization& call_optimization, int accessor_index) {
570 Register holder = Frontend(name);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100571 if (FLAG_runtime_call_stats) {
572 GenerateRestoreName(name);
573 TailCallBuiltin(masm(), Builtins::kStoreIC_Slow);
574 } else {
575 GenerateApiAccessorCall(masm(), call_optimization, handle(object->map()),
576 receiver(), scratch2(), true, value(), holder,
577 accessor_index);
578 }
Ben Murdochc5610432016-08-08 18:44:38 +0100579 return GetCode(kind(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000580}
581
582
583#undef __
584
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000585void ElementHandlerCompiler::CompileElementHandlers(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100586 MapHandleList* receiver_maps, CodeHandleList* handlers) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000587 for (int i = 0; i < receiver_maps->length(); ++i) {
588 Handle<Map> receiver_map = receiver_maps->at(i);
589 Handle<Code> cached_stub;
590
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400591 if (receiver_map->IsStringMap()) {
592 cached_stub = LoadIndexedStringStub(isolate()).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000593 } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100594 cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000595 } else {
596 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
597 ElementsKind elements_kind = receiver_map->elements_kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000598
599 // No need to check for an elements-free prototype chain here, the
600 // generated stub code needs to check that dynamically anyway.
601 bool convert_hole_to_undefined =
602 (is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
Ben Murdoch097c5b22016-05-18 11:27:45 +0100603 *receiver_map == isolate()->get_initial_js_array_map(elements_kind));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000604
Ben Murdochda12d292016-06-02 14:46:10 +0100605 if (receiver_map->has_indexed_interceptor() &&
Ben Murdoch61f157c2016-09-16 13:49:30 +0100606 !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(
607 isolate()) &&
Ben Murdochda12d292016-06-02 14:46:10 +0100608 !receiver_map->GetIndexedInterceptor()->non_masking()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000609 cached_stub = LoadIndexedInterceptorStub(isolate()).GetCode();
610 } else if (IsSloppyArgumentsElements(elements_kind)) {
611 cached_stub = KeyedLoadSloppyArgumentsStub(isolate()).GetCode();
612 } else if (IsFastElementsKind(elements_kind) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000613 IsFixedTypedArrayElementsKind(elements_kind)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000614 cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind,
615 convert_hole_to_undefined).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000616 } else {
617 DCHECK(elements_kind == DICTIONARY_ELEMENTS);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100618 cached_stub = LoadDictionaryElementStub(isolate()).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000619 }
620 }
621
622 handlers->Add(cached_stub);
623 }
624}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000625} // namespace internal
626} // namespace v8