Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(275)

Side by Side Diff: src/mips/stub-cache-mips.cc

Issue 83483005: MIPS: Use Type in CheckPrototypes. (Closed) Base URL: https://github.com/v8/v8.git@gbl
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 1007 matching lines...) Expand 10 before | Expand all | Expand 10 after
1018 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1, 1018 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
1019 scratch1, scratch2); 1019 scratch1, scratch2);
1020 ReserveSpaceForFastApiCall(masm, scratch1); 1020 ReserveSpaceForFastApiCall(masm, scratch1);
1021 } 1021 }
1022 1022
1023 // Check that the maps from receiver to interceptor's holder 1023 // Check that the maps from receiver to interceptor's holder
1024 // haven't changed and thus we can invoke interceptor. 1024 // haven't changed and thus we can invoke interceptor.
1025 Label miss_cleanup; 1025 Label miss_cleanup;
1026 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; 1026 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
1027 Register holder = 1027 Register holder =
1028 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, 1028 stub_compiler_->CheckPrototypes(
1029 scratch1, scratch2, scratch3, 1029 IC::CurrentTypeOf(object, masm->isolate()), receiver,
1030 name, depth1, miss); 1030 interceptor_holder, scratch1, scratch2, scratch3,
1031 name, depth1, miss);
1031 1032
1032 // Invoke an interceptor and if it provides a value, 1033 // Invoke an interceptor and if it provides a value,
1033 // branch to |regular_invoke|. 1034 // branch to |regular_invoke|.
1034 Label regular_invoke; 1035 Label regular_invoke;
1035 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2, 1036 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
1036 &regular_invoke); 1037 &regular_invoke);
1037 1038
1038 // Interceptor returned nothing for this property. Try to use cached 1039 // Interceptor returned nothing for this property. Try to use cached
1039 // constant function. 1040 // constant function.
1040 1041
1041 // Check that the maps from interceptor's holder to constant function's 1042 // Check that the maps from interceptor's holder to constant function's
1042 // holder haven't changed and thus we can use cached constant function. 1043 // holder haven't changed and thus we can use cached constant function.
1043 if (*interceptor_holder != lookup->holder()) { 1044 if (*interceptor_holder != lookup->holder()) {
1044 stub_compiler_->CheckPrototypes(interceptor_holder, receiver, 1045 stub_compiler_->CheckPrototypes(
1045 Handle<JSObject>(lookup->holder()), 1046 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), receiver,
1046 scratch1, scratch2, scratch3, 1047 handle(lookup->holder()), scratch1, scratch2, scratch3,
1047 name, depth2, miss); 1048 name, depth2, miss);
1048 } else { 1049 } else {
1049 // CheckPrototypes has a side effect of fetching a 'holder' 1050 // CheckPrototypes has a side effect of fetching a 'holder'
1050 // for API (object which is instanceof for the signature). It's 1051 // for API (object which is instanceof for the signature). It's
1051 // safe to omit it here, as if present, it should be fetched 1052 // safe to omit it here, as if present, it should be fetched
1052 // by the previous CheckPrototypes. 1053 // by the previous CheckPrototypes.
1053 ASSERT(depth2 == kInvalidProtoDepth); 1054 ASSERT(depth2 == kInvalidProtoDepth);
1054 } 1055 }
1055 1056
1056 // Invoke function. 1057 // Invoke function.
1057 if (can_do_fast_api_call) { 1058 if (can_do_fast_api_call) {
(...skipping 26 matching lines...) Expand all
1084 void CompileRegular(MacroAssembler* masm, 1085 void CompileRegular(MacroAssembler* masm,
1085 Handle<JSObject> object, 1086 Handle<JSObject> object,
1086 Register receiver, 1087 Register receiver,
1087 Register scratch1, 1088 Register scratch1,
1088 Register scratch2, 1089 Register scratch2,
1089 Register scratch3, 1090 Register scratch3,
1090 Handle<Name> name, 1091 Handle<Name> name,
1091 Handle<JSObject> interceptor_holder, 1092 Handle<JSObject> interceptor_holder,
1092 Label* miss_label) { 1093 Label* miss_label) {
1093 Register holder = 1094 Register holder =
1094 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, 1095 stub_compiler_->CheckPrototypes(
1095 scratch1, scratch2, scratch3, 1096 IC::CurrentTypeOf(object, masm->isolate()), receiver,
1096 name, miss_label); 1097 interceptor_holder, scratch1, scratch2, scratch3, name, miss_label);
1097 1098
1098 // Call a runtime function to load the interceptor property. 1099 // Call a runtime function to load the interceptor property.
1099 FrameScope scope(masm, StackFrame::INTERNAL); 1100 FrameScope scope(masm, StackFrame::INTERNAL);
1100 // Save the name_ register across the call. 1101 // Save the name_ register across the call.
1101 __ push(name_); 1102 __ push(name_);
1102 1103
1103 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder); 1104 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
1104 1105
1105 __ CallExternalReference( 1106 __ CallExternalReference(
1106 ExternalReference( 1107 ExternalReference(
(...skipping 28 matching lines...) Expand all
1135 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch)); 1136 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
1136 } 1137 }
1137 1138
1138 StubCompiler* stub_compiler_; 1139 StubCompiler* stub_compiler_;
1139 const ParameterCount& arguments_; 1140 const ParameterCount& arguments_;
1140 Register name_; 1141 Register name_;
1141 Code::ExtraICState extra_ic_state_; 1142 Code::ExtraICState extra_ic_state_;
1142 }; 1143 };
1143 1144
1144 1145
1145 void StubCompiler::GenerateCheckPropertyCells(MacroAssembler* masm,
1146 Handle<JSObject> object,
1147 Handle<JSObject> holder,
1148 Handle<Name> name,
1149 Register scratch,
1150 Label* miss) {
1151 Handle<JSObject> current = object;
1152 while (!current.is_identical_to(holder)) {
1153 if (current->IsJSGlobalObject()) {
1154 GenerateCheckPropertyCell(masm,
1155 Handle<JSGlobalObject>::cast(current),
1156 name,
1157 scratch,
1158 miss);
1159 }
1160 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1161 }
1162 }
1163
1164
1165 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { 1146 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
1166 __ Jump(code, RelocInfo::CODE_TARGET); 1147 __ Jump(code, RelocInfo::CODE_TARGET);
1167 } 1148 }
1168 1149
1169 1150
1170 #undef __ 1151 #undef __
1171 #define __ ACCESS_MASM(masm()) 1152 #define __ ACCESS_MASM(masm())
1172 1153
1173 1154
1174 Register StubCompiler::CheckPrototypes(Handle<JSObject> object, 1155 Register StubCompiler::CheckPrototypes(Handle<Type> type,
1175 Register object_reg, 1156 Register object_reg,
1176 Handle<JSObject> holder, 1157 Handle<JSObject> holder,
1177 Register holder_reg, 1158 Register holder_reg,
1178 Register scratch1, 1159 Register scratch1,
1179 Register scratch2, 1160 Register scratch2,
1180 Handle<Name> name, 1161 Handle<Name> name,
1181 int save_at_depth, 1162 int save_at_depth,
1182 Label* miss, 1163 Label* miss,
1183 PrototypeCheckType check) { 1164 PrototypeCheckType check) {
1165 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate()));
1184 // Make sure that the type feedback oracle harvests the receiver map. 1166 // Make sure that the type feedback oracle harvests the receiver map.
1185 // TODO(svenpanne) Remove this hack when all ICs are reworked. 1167 // TODO(svenpanne) Remove this hack when all ICs are reworked.
1186 __ li(scratch1, Operand(Handle<Map>(object->map()))); 1168 __ li(scratch1, Operand(receiver_map));
1187 1169
1188 Handle<JSObject> first = object;
1189 // Make sure there's no overlap between holder and object registers. 1170 // Make sure there's no overlap between holder and object registers.
1190 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); 1171 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1191 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) 1172 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1192 && !scratch2.is(scratch1)); 1173 && !scratch2.is(scratch1));
1193 1174
1194 // Keep track of the current object in register reg. 1175 // Keep track of the current object in register reg.
1195 Register reg = object_reg; 1176 Register reg = object_reg;
1196 int depth = 0; 1177 int depth = 0;
1197 1178
1198 typedef FunctionCallbackArguments FCA; 1179 typedef FunctionCallbackArguments FCA;
1199 if (save_at_depth == depth) { 1180 if (save_at_depth == depth) {
1200 __ sw(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize)); 1181 __ sw(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize));
1201 } 1182 }
1202 1183
1203 // Check the maps in the prototype chain. 1184 Handle<JSObject> current = Handle<JSObject>::null();
1204 // Traverse the prototype chain from the object and do map checks. 1185 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant());
1205 Handle<JSObject> current = object; 1186 Handle<JSObject> prototype = Handle<JSObject>::null();
1206 while (!current.is_identical_to(holder)) { 1187 Handle<Map> current_map = receiver_map;
1188 Handle<Map> holder_map(holder->map());
1189 // Traverse the prototype chain and check the maps in the prototype chain for
1190 // fast and global objects or do negative lookup for normal objects.
1191 while (!current_map.is_identical_to(holder_map)) {
1207 ++depth; 1192 ++depth;
1208 1193
1209 // Only global objects and objects that do not require access 1194 // Only global objects and objects that do not require access
1210 // checks are allowed in stubs. 1195 // checks are allowed in stubs.
1211 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); 1196 ASSERT(current_map->IsJSGlobalProxyMap() ||
1197 !current_map->is_access_check_needed());
1212 1198
1213 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype())); 1199 prototype = handle(JSObject::cast(current_map->prototype()));
1214 if (!current->HasFastProperties() && 1200 if (current_map->is_dictionary_map() &&
1215 !current->IsJSGlobalObject() && 1201 !current_map->IsJSGlobalObjectMap() &&
1216 !current->IsJSGlobalProxy()) { 1202 !current_map->IsJSGlobalProxyMap()) {
1217 if (!name->IsUniqueName()) { 1203 if (!name->IsUniqueName()) {
1218 ASSERT(name->IsString()); 1204 ASSERT(name->IsString());
1219 name = factory()->InternalizeString(Handle<String>::cast(name)); 1205 name = factory()->InternalizeString(Handle<String>::cast(name));
1220 } 1206 }
1221 ASSERT(current->property_dictionary()->FindEntry(*name) == 1207 ASSERT(current.is_null() ||
1208 current->property_dictionary()->FindEntry(*name) ==
1222 NameDictionary::kNotFound); 1209 NameDictionary::kNotFound);
1223 1210
1224 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, 1211 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1225 scratch1, scratch2); 1212 scratch1, scratch2);
1226 1213
1227 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); 1214 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1228 reg = holder_reg; // From now on the object will be in holder_reg. 1215 reg = holder_reg; // From now on the object will be in holder_reg.
1229 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); 1216 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1230 } else { 1217 } else {
1231 Register map_reg = scratch1; 1218 Register map_reg = scratch1;
1232 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) { 1219 if (depth != 1 || check == CHECK_ALL_MAPS) {
1233 Handle<Map> current_map(current->map());
1234 // CheckMap implicitly loads the map of |reg| into |map_reg|. 1220 // CheckMap implicitly loads the map of |reg| into |map_reg|.
1235 __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK); 1221 __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK);
1236 } else { 1222 } else {
1237 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); 1223 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
1238 } 1224 }
1225
1239 // Check access rights to the global object. This has to happen after 1226 // Check access rights to the global object. This has to happen after
1240 // the map check so that we know that the object is actually a global 1227 // the map check so that we know that the object is actually a global
1241 // object. 1228 // object.
1242 if (current->IsJSGlobalProxy()) { 1229 if (current_map->IsJSGlobalProxyMap()) {
1243 __ CheckAccessGlobalProxy(reg, scratch2, miss); 1230 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1231 } else if (current_map->IsJSGlobalObjectMap()) {
1232 GenerateCheckPropertyCell(
1233 masm(), Handle<JSGlobalObject>::cast(current), name,
1234 scratch2, miss);
1244 } 1235 }
1236
1245 reg = holder_reg; // From now on the object will be in holder_reg. 1237 reg = holder_reg; // From now on the object will be in holder_reg.
1246 1238
1247 if (heap()->InNewSpace(*prototype)) { 1239 if (heap()->InNewSpace(*prototype)) {
1248 // The prototype is in new space; we cannot store a reference to it 1240 // The prototype is in new space; we cannot store a reference to it
1249 // in the code. Load it from the map. 1241 // in the code. Load it from the map.
1250 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); 1242 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
1251 } else { 1243 } else {
1252 // The prototype is in old space; load it directly. 1244 // The prototype is in old space; load it directly.
1253 __ li(reg, Operand(prototype)); 1245 __ li(reg, Operand(prototype));
1254 } 1246 }
1255 } 1247 }
1256 1248
1257 if (save_at_depth == depth) { 1249 if (save_at_depth == depth) {
1258 __ sw(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize)); 1250 __ sw(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize));
1259 } 1251 }
1260 1252
1261 // Go to the next object in the prototype chain. 1253 // Go to the next object in the prototype chain.
1262 current = prototype; 1254 current = prototype;
1255 current_map = handle(current->map());
1263 } 1256 }
1264 1257
1265 // Log the check depth. 1258 // Log the check depth.
1266 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); 1259 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1267 1260
1268 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) { 1261 if (depth != 0 || check == CHECK_ALL_MAPS) {
1269 // Check the holder map. 1262 // Check the holder map.
1270 __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss, 1263 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK);
1271 DONT_DO_SMI_CHECK);
1272 } 1264 }
1273 1265
1274 // Perform security check for access to the global object. 1266 // Perform security check for access to the global object.
1275 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); 1267 ASSERT(current_map->IsJSGlobalProxyMap() ||
1276 if (holder->IsJSGlobalProxy()) { 1268 !current_map->is_access_check_needed());
1269 if (current_map->IsJSGlobalProxyMap()) {
1277 __ CheckAccessGlobalProxy(reg, scratch1, miss); 1270 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1278 } 1271 }
1279 1272
1280 // If we've skipped any global objects, it's not enough to verify that
1281 // their maps haven't changed. We also need to check that the property
1282 // cell for the property is still empty.
1283 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1284
1285 // Return the register containing the holder. 1273 // Return the register containing the holder.
1286 return reg; 1274 return reg;
1287 } 1275 }
1288 1276
1289 1277
1290 void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) { 1278 void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
1291 if (!miss->is_unused()) { 1279 if (!miss->is_unused()) {
1292 Label success; 1280 Label success;
1293 __ Branch(&success); 1281 __ Branch(&success);
1294 __ bind(miss); 1282 __ bind(miss);
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
1557 ASSERT(holder->IsGlobalObject()); 1545 ASSERT(holder->IsGlobalObject());
1558 1546
1559 // Get the number of arguments. 1547 // Get the number of arguments.
1560 const int argc = arguments().immediate(); 1548 const int argc = arguments().immediate();
1561 1549
1562 // Get the receiver from the stack. 1550 // Get the receiver from the stack.
1563 __ lw(a0, MemOperand(sp, argc * kPointerSize)); 1551 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1564 1552
1565 // Check that the maps haven't changed. 1553 // Check that the maps haven't changed.
1566 __ JumpIfSmi(a0, miss); 1554 __ JumpIfSmi(a0, miss);
1567 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss); 1555 CheckPrototypes(
1556 IC::CurrentTypeOf(object, isolate()), a0, holder, a3, a1, t0, name, miss);
1568 } 1557 }
1569 1558
1570 1559
1571 void CallStubCompiler::GenerateLoadFunctionFromCell( 1560 void CallStubCompiler::GenerateLoadFunctionFromCell(
1572 Handle<Cell> cell, 1561 Handle<Cell> cell,
1573 Handle<JSFunction> function, 1562 Handle<JSFunction> function,
1574 Label* miss) { 1563 Label* miss) {
1575 // Get the value from the cell. 1564 // Get the value from the cell.
1576 __ li(a3, Operand(cell)); 1565 __ li(a3, Operand(cell));
1577 __ lw(a1, FieldMemOperand(a3, Cell::kValueOffset)); 1566 __ lw(a1, FieldMemOperand(a3, Cell::kValueOffset));
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1619 GenerateNameCheck(name, &miss); 1608 GenerateNameCheck(name, &miss);
1620 1609
1621 const int argc = arguments().immediate(); 1610 const int argc = arguments().immediate();
1622 1611
1623 // Get the receiver of the function from the stack into a0. 1612 // Get the receiver of the function from the stack into a0.
1624 __ lw(a0, MemOperand(sp, argc * kPointerSize)); 1613 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1625 // Check that the receiver isn't a smi. 1614 // Check that the receiver isn't a smi.
1626 __ JumpIfSmi(a0, &miss, t0); 1615 __ JumpIfSmi(a0, &miss, t0);
1627 1616
1628 // Do the right check and compute the holder register. 1617 // Do the right check and compute the holder register.
1629 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss); 1618 Register reg = CheckPrototypes(
1619 IC::CurrentTypeOf(object, isolate()),
1620 a0, holder, a1, a3, t0, name, &miss);
1630 GenerateFastPropertyLoad(masm(), a1, reg, index.is_inobject(holder), 1621 GenerateFastPropertyLoad(masm(), a1, reg, index.is_inobject(holder),
1631 index.translate(holder), Representation::Tagged()); 1622 index.translate(holder), Representation::Tagged());
1632 1623
1633 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_); 1624 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
1634 1625
1635 // Handle call cache miss. 1626 // Handle call cache miss.
1636 __ bind(&miss); 1627 __ bind(&miss);
1637 GenerateMissBranch(); 1628 GenerateMissBranch();
1638 1629
1639 // Return the generated code. 1630 // Return the generated code.
(...skipping 15 matching lines...) Expand all
1655 GenerateNameCheck(name, &miss); 1646 GenerateNameCheck(name, &miss);
1656 Register receiver = a1; 1647 Register receiver = a1;
1657 1648
1658 if (cell.is_null()) { 1649 if (cell.is_null()) {
1659 __ lw(receiver, MemOperand(sp, argc * kPointerSize)); 1650 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1660 1651
1661 // Check that the receiver isn't a smi. 1652 // Check that the receiver isn't a smi.
1662 __ JumpIfSmi(receiver, &miss); 1653 __ JumpIfSmi(receiver, &miss);
1663 1654
1664 // Check that the maps haven't changed. 1655 // Check that the maps haven't changed.
1665 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, a0, 1656 CheckPrototypes(
1666 t0, name, &miss); 1657 IC::CurrentTypeOf(object, isolate()), receiver, holder,
1658 a3, a0, t0, name, &miss);
1667 } else { 1659 } else {
1668 ASSERT(cell->value() == *function); 1660 ASSERT(cell->value() == *function);
1669 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, 1661 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1670 &miss); 1662 &miss);
1671 GenerateLoadFunctionFromCell(cell, function, &miss); 1663 GenerateLoadFunctionFromCell(cell, function, &miss);
1672 } 1664 }
1673 1665
1674 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite(); 1666 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite();
1675 site->SetElementsKind(GetInitialFastElementsKind()); 1667 site->SetElementsKind(GetInitialFastElementsKind());
1676 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site); 1668 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site);
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1718 Register receiver = a1; 1710 Register receiver = a1;
1719 1711
1720 // Get the receiver from the stack. 1712 // Get the receiver from the stack.
1721 const int argc = arguments().immediate(); 1713 const int argc = arguments().immediate();
1722 __ lw(receiver, MemOperand(sp, argc * kPointerSize)); 1714 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1723 1715
1724 // Check that the receiver isn't a smi. 1716 // Check that the receiver isn't a smi.
1725 __ JumpIfSmi(receiver, &miss); 1717 __ JumpIfSmi(receiver, &miss);
1726 1718
1727 // Check that the maps haven't changed. 1719 // Check that the maps haven't changed.
1728 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0, 1720 CheckPrototypes(
1729 name, &miss); 1721 IC::CurrentTypeOf(object, isolate()), receiver, holder,
1722 a3, v0, t0, name, &miss);
1730 1723
1731 if (argc == 0) { 1724 if (argc == 0) {
1732 // Nothing to do, just return the length. 1725 // Nothing to do, just return the length.
1733 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset)); 1726 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1734 __ DropAndRet(argc + 1); 1727 __ DropAndRet(argc + 1);
1735 } else { 1728 } else {
1736 Label call_builtin; 1729 Label call_builtin;
1737 if (argc == 1) { // Otherwise fall through to call the builtin. 1730 if (argc == 1) { // Otherwise fall through to call the builtin.
1738 Label attempt_to_grow_elements, with_write_barrier, check_double; 1731 Label attempt_to_grow_elements, with_write_barrier, check_double;
1739 1732
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
1975 Register elements = a3; 1968 Register elements = a3;
1976 GenerateNameCheck(name, &miss); 1969 GenerateNameCheck(name, &miss);
1977 1970
1978 // Get the receiver from the stack. 1971 // Get the receiver from the stack.
1979 const int argc = arguments().immediate(); 1972 const int argc = arguments().immediate();
1980 __ lw(receiver, MemOperand(sp, argc * kPointerSize)); 1973 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1981 // Check that the receiver isn't a smi. 1974 // Check that the receiver isn't a smi.
1982 __ JumpIfSmi(receiver, &miss); 1975 __ JumpIfSmi(receiver, &miss);
1983 1976
1984 // Check that the maps haven't changed. 1977 // Check that the maps haven't changed.
1985 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements, 1978 CheckPrototypes(
1986 t0, v0, name, &miss); 1979 IC::CurrentTypeOf(object, isolate()), receiver, holder,
1980 elements, t0, v0, name, &miss);
1987 1981
1988 // Get the elements array of the object. 1982 // Get the elements array of the object.
1989 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); 1983 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1990 1984
1991 // Check that the elements are in fast mode and writable. 1985 // Check that the elements are in fast mode and writable.
1992 __ CheckMap(elements, 1986 __ CheckMap(elements,
1993 v0, 1987 v0,
1994 Heap::kFixedArrayMapRootIndex, 1988 Heap::kFixedArrayMapRootIndex,
1995 &call_builtin, 1989 &call_builtin,
1996 DONT_DO_SMI_CHECK); 1990 DONT_DO_SMI_CHECK);
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
2067 } 2061 }
2068 2062
2069 GenerateNameCheck(name, &name_miss); 2063 GenerateNameCheck(name, &name_miss);
2070 2064
2071 // Check that the maps starting from the prototype haven't changed. 2065 // Check that the maps starting from the prototype haven't changed.
2072 GenerateDirectLoadGlobalFunctionPrototype(masm(), 2066 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2073 Context::STRING_FUNCTION_INDEX, 2067 Context::STRING_FUNCTION_INDEX,
2074 v0, 2068 v0,
2075 &miss); 2069 &miss);
2076 ASSERT(!object.is_identical_to(holder)); 2070 ASSERT(!object.is_identical_to(holder));
2071 Handle<JSObject> prototype(JSObject::cast(object->GetPrototype(isolate())));
2077 CheckPrototypes( 2072 CheckPrototypes(
2078 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), 2073 IC::CurrentTypeOf(prototype, isolate()),
2079 v0, holder, a1, a3, t0, name, &miss); 2074 v0, holder, a1, a3, t0, name, &miss);
2080 2075
2081 Register receiver = a1; 2076 Register receiver = a1;
2082 Register index = t1; 2077 Register index = t1;
2083 Register result = v0; 2078 Register result = v0;
2084 __ lw(receiver, MemOperand(sp, argc * kPointerSize)); 2079 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2085 if (argc > 0) { 2080 if (argc > 0) {
2086 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize)); 2081 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2087 } else { 2082 } else {
2088 __ LoadRoot(index, Heap::kUndefinedValueRootIndex); 2083 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
2147 index_out_of_range_label = &miss; 2142 index_out_of_range_label = &miss;
2148 } 2143 }
2149 GenerateNameCheck(name, &name_miss); 2144 GenerateNameCheck(name, &name_miss);
2150 2145
2151 // Check that the maps starting from the prototype haven't changed. 2146 // Check that the maps starting from the prototype haven't changed.
2152 GenerateDirectLoadGlobalFunctionPrototype(masm(), 2147 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2153 Context::STRING_FUNCTION_INDEX, 2148 Context::STRING_FUNCTION_INDEX,
2154 v0, 2149 v0,
2155 &miss); 2150 &miss);
2156 ASSERT(!object.is_identical_to(holder)); 2151 ASSERT(!object.is_identical_to(holder));
2152 Handle<JSObject> prototype(JSObject::cast(object->GetPrototype(isolate())));
2157 CheckPrototypes( 2153 CheckPrototypes(
2158 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), 2154 IC::CurrentTypeOf(prototype, isolate()),
2159 v0, holder, a1, a3, t0, name, &miss); 2155 v0, holder, a1, a3, t0, name, &miss);
2160 2156
2161 Register receiver = v0; 2157 Register receiver = v0;
2162 Register index = t1; 2158 Register index = t1;
2163 Register scratch = a3; 2159 Register scratch = a3;
2164 Register result = v0; 2160 Register result = v0;
2165 __ lw(receiver, MemOperand(sp, argc * kPointerSize)); 2161 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2166 if (argc > 0) { 2162 if (argc > 0) {
2167 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize)); 2163 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2168 } else { 2164 } else {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
2223 2219
2224 Label miss; 2220 Label miss;
2225 GenerateNameCheck(name, &miss); 2221 GenerateNameCheck(name, &miss);
2226 2222
2227 if (cell.is_null()) { 2223 if (cell.is_null()) {
2228 __ lw(a1, MemOperand(sp, 1 * kPointerSize)); 2224 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2229 2225
2230 STATIC_ASSERT(kSmiTag == 0); 2226 STATIC_ASSERT(kSmiTag == 0);
2231 __ JumpIfSmi(a1, &miss); 2227 __ JumpIfSmi(a1, &miss);
2232 2228
2233 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0, 2229 CheckPrototypes(
2234 name, &miss); 2230 IC::CurrentTypeOf(object, isolate()),
2231 a1, holder, v0, a3, t0, name, &miss);
2235 } else { 2232 } else {
2236 ASSERT(cell->value() == *function); 2233 ASSERT(cell->value() == *function);
2237 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, 2234 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2238 &miss); 2235 &miss);
2239 GenerateLoadFunctionFromCell(cell, function, &miss); 2236 GenerateLoadFunctionFromCell(cell, function, &miss);
2240 } 2237 }
2241 2238
2242 // Load the char code argument. 2239 // Load the char code argument.
2243 Register code = a1; 2240 Register code = a1;
2244 __ lw(code, MemOperand(sp, 0 * kPointerSize)); 2241 __ lw(code, MemOperand(sp, 0 * kPointerSize));
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
2295 // arguments, bail out to the regular call. 2292 // arguments, bail out to the regular call.
2296 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null(); 2293 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
2297 2294
2298 Label miss, slow; 2295 Label miss, slow;
2299 GenerateNameCheck(name, &miss); 2296 GenerateNameCheck(name, &miss);
2300 2297
2301 if (cell.is_null()) { 2298 if (cell.is_null()) {
2302 __ lw(a1, MemOperand(sp, 1 * kPointerSize)); 2299 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2303 STATIC_ASSERT(kSmiTag == 0); 2300 STATIC_ASSERT(kSmiTag == 0);
2304 __ JumpIfSmi(a1, &miss); 2301 __ JumpIfSmi(a1, &miss);
2305 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, 2302 CheckPrototypes(
2306 name, &miss); 2303 IC::CurrentTypeOf(object, isolate()),
2304 a1, holder, a0, a3, t0, name, &miss);
2307 } else { 2305 } else {
2308 ASSERT(cell->value() == *function); 2306 ASSERT(cell->value() == *function);
2309 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, 2307 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2310 &miss); 2308 &miss);
2311 GenerateLoadFunctionFromCell(cell, function, &miss); 2309 GenerateLoadFunctionFromCell(cell, function, &miss);
2312 } 2310 }
2313 2311
2314 // Load the (only) argument into v0. 2312 // Load the (only) argument into v0.
2315 __ lw(v0, MemOperand(sp, 0 * kPointerSize)); 2313 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2316 2314
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
2424 // arguments, bail out to the regular call. 2422 // arguments, bail out to the regular call.
2425 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null(); 2423 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
2426 2424
2427 Label miss; 2425 Label miss;
2428 2426
2429 GenerateNameCheck(name, &miss); 2427 GenerateNameCheck(name, &miss);
2430 if (cell.is_null()) { 2428 if (cell.is_null()) {
2431 __ lw(a1, MemOperand(sp, 1 * kPointerSize)); 2429 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2432 STATIC_ASSERT(kSmiTag == 0); 2430 STATIC_ASSERT(kSmiTag == 0);
2433 __ JumpIfSmi(a1, &miss); 2431 __ JumpIfSmi(a1, &miss);
2434 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0, 2432 CheckPrototypes(
2435 name, &miss); 2433 IC::CurrentTypeOf(object, isolate()),
2434 a1, holder, v0, a3, t0, name, &miss);
2436 } else { 2435 } else {
2437 ASSERT(cell->value() == *function); 2436 ASSERT(cell->value() == *function);
2438 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, 2437 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2439 &miss); 2438 &miss);
2440 GenerateLoadFunctionFromCell(cell, function, &miss); 2439 GenerateLoadFunctionFromCell(cell, function, &miss);
2441 } 2440 }
2442 2441
2443 // Load the (only) argument into v0. 2442 // Load the (only) argument into v0.
2444 __ lw(v0, MemOperand(sp, 0 * kPointerSize)); 2443 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2445 2444
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
2534 2533
2535 // Check that the receiver isn't a smi. 2534 // Check that the receiver isn't a smi.
2536 __ JumpIfSmi(a1, &miss_before_stack_reserved); 2535 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2537 2536
2538 __ IncrementCounter(counters->call_const(), 1, a0, a3); 2537 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2539 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3); 2538 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2540 2539
2541 ReserveSpaceForFastApiCall(masm(), a0); 2540 ReserveSpaceForFastApiCall(masm(), a0);
2542 2541
2543 // Check that the maps haven't changed and find a Holder as a side effect. 2542 // Check that the maps haven't changed and find a Holder as a side effect.
2544 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name, 2543 CheckPrototypes(
2545 depth, &miss); 2544 IC::CurrentTypeOf(object, isolate()),
2545 a1, holder, a0, a3, t0, name, depth, &miss);
2546 2546
2547 GenerateFastApiDirectCall(masm(), optimization, argc, false); 2547 GenerateFastApiDirectCall(masm(), optimization, argc, false);
2548 2548
2549 __ bind(&miss); 2549 __ bind(&miss);
2550 FreeSpaceForFastApiCall(masm()); 2550 FreeSpaceForFastApiCall(masm());
2551 2551
2552 __ bind(&miss_before_stack_reserved); 2552 __ bind(&miss_before_stack_reserved);
2553 GenerateMissBranch(); 2553 GenerateMissBranch();
2554 2554
2555 // Return the generated code. 2555 // Return the generated code.
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
2589 } 2589 }
2590 2590
2591 // Make sure that it's okay not to patch the on stack receiver 2591 // Make sure that it's okay not to patch the on stack receiver
2592 // unless we're doing a receiver map check. 2592 // unless we're doing a receiver map check.
2593 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); 2593 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2594 switch (check) { 2594 switch (check) {
2595 case RECEIVER_MAP_CHECK: 2595 case RECEIVER_MAP_CHECK:
2596 __ IncrementCounter(isolate()->counters()->call_const(), 1, a0, a3); 2596 __ IncrementCounter(isolate()->counters()->call_const(), 1, a0, a3);
2597 2597
2598 // Check that the maps haven't changed. 2598 // Check that the maps haven't changed.
2599 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, 2599 CheckPrototypes(
2600 name, &miss); 2600 IC::CurrentTypeOf(object, isolate()),
2601 a1, holder, a0, a3, t0, name, &miss);
2601 2602
2602 // Patch the receiver on the stack with the global proxy if 2603 // Patch the receiver on the stack with the global proxy if
2603 // necessary. 2604 // necessary.
2604 if (object->IsGlobalObject()) { 2605 if (object->IsGlobalObject()) {
2605 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset)); 2606 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2606 __ sw(a3, MemOperand(sp, argc * kPointerSize)); 2607 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2607 } 2608 }
2608 break; 2609 break;
2609 2610
2610 case STRING_CHECK: 2611 case STRING_CHECK: {
2611 // Check that the object is a string. 2612 // Check that the object is a string.
2612 __ GetObjectType(a1, a3, a3); 2613 __ GetObjectType(a1, a3, a3);
2613 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE)); 2614 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2614 // Check that the maps starting from the prototype haven't changed. 2615 // Check that the maps starting from the prototype haven't changed.
2615 GenerateDirectLoadGlobalFunctionPrototype( 2616 GenerateDirectLoadGlobalFunctionPrototype(
2616 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss); 2617 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2618 Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
2617 CheckPrototypes( 2619 CheckPrototypes(
2618 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), 2620 IC::CurrentTypeOf(prototype, isolate()),
2619 a0, holder, a3, a1, t0, name, &miss); 2621 a0, holder, a3, a1, t0, name, &miss);
2620 break; 2622 break;
2621 2623 }
2622 case SYMBOL_CHECK: 2624 case SYMBOL_CHECK: {
2623 // Check that the object is a symbol. 2625 // Check that the object is a symbol.
2624 __ GetObjectType(a1, a1, a3); 2626 __ GetObjectType(a1, a1, a3);
2625 __ Branch(&miss, ne, a3, Operand(SYMBOL_TYPE)); 2627 __ Branch(&miss, ne, a3, Operand(SYMBOL_TYPE));
2626 // Check that the maps starting from the prototype haven't changed. 2628 // Check that the maps starting from the prototype haven't changed.
2627 GenerateDirectLoadGlobalFunctionPrototype( 2629 GenerateDirectLoadGlobalFunctionPrototype(
2628 masm(), Context::SYMBOL_FUNCTION_INDEX, a0, &miss); 2630 masm(), Context::SYMBOL_FUNCTION_INDEX, a0, &miss);
2631 Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
2629 CheckPrototypes( 2632 CheckPrototypes(
2630 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), 2633 IC::CurrentTypeOf(prototype, isolate()),
2631 a0, holder, a3, a1, t0, name, &miss); 2634 a0, holder, a3, a1, t0, name, &miss);
2632 break; 2635 break;
2633 2636 }
2634 case NUMBER_CHECK: { 2637 case NUMBER_CHECK: {
2635 Label fast; 2638 Label fast;
2636 // Check that the object is a smi or a heap number. 2639 // Check that the object is a smi or a heap number.
2637 __ JumpIfSmi(a1, &fast); 2640 __ JumpIfSmi(a1, &fast);
2638 __ GetObjectType(a1, a0, a0); 2641 __ GetObjectType(a1, a0, a0);
2639 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE)); 2642 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2640 __ bind(&fast); 2643 __ bind(&fast);
2641 // Check that the maps starting from the prototype haven't changed. 2644 // Check that the maps starting from the prototype haven't changed.
2642 GenerateDirectLoadGlobalFunctionPrototype( 2645 GenerateDirectLoadGlobalFunctionPrototype(
2643 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss); 2646 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2647 Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
2644 CheckPrototypes( 2648 CheckPrototypes(
2645 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), 2649 IC::CurrentTypeOf(prototype, isolate()),
2646 a0, holder, a3, a1, t0, name, &miss); 2650 a0, holder, a3, a1, t0, name, &miss);
2647 break; 2651 break;
2648 } 2652 }
2649 case BOOLEAN_CHECK: { 2653 case BOOLEAN_CHECK: {
2650 GenerateBooleanCheck(a1, &miss); 2654 GenerateBooleanCheck(a1, &miss);
2651 2655
2652 // Check that the maps starting from the prototype haven't changed. 2656 // Check that the maps starting from the prototype haven't changed.
2653 GenerateDirectLoadGlobalFunctionPrototype( 2657 GenerateDirectLoadGlobalFunctionPrototype(
2654 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss); 2658 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2659 Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
2655 CheckPrototypes( 2660 CheckPrototypes(
2656 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), 2661 IC::CurrentTypeOf(prototype, isolate()),
2657 a0, holder, a3, a1, t0, name, &miss); 2662 a0, holder, a3, a1, t0, name, &miss);
2658 break; 2663 break;
2659 } 2664 }
2660 } 2665 }
2661 2666
2662 Label success; 2667 Label success;
2663 __ Branch(&success); 2668 __ Branch(&success);
2664 2669
2665 // Handle call cache miss. 2670 // Handle call cache miss.
2666 __ bind(&miss); 2671 __ bind(&miss);
(...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after
3183 // ----------------------------------- 3188 // -----------------------------------
3184 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); 3189 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss);
3185 } 3190 }
3186 3191
3187 3192
3188 #undef __ 3193 #undef __
3189 3194
3190 } } // namespace v8::internal 3195 } } // namespace v8::internal
3191 3196
3192 #endif // V8_TARGET_ARCH_MIPS 3197 #endif // V8_TARGET_ARCH_MIPS
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698