OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stdlib.h> | 5 #include <stdlib.h> |
6 #include <limits> | 6 #include <limits> |
7 | 7 |
8 #include "src/v8.h" | 8 #include "src/v8.h" |
9 | 9 |
10 #include "src/accessors.h" | 10 #include "src/accessors.h" |
(...skipping 622 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
633 Handle<Object> privates; | 633 Handle<Object> privates; |
634 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 634 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
635 isolate, privates, Object::GetPropertyOrElement(registry, part)); | 635 isolate, privates, Object::GetPropertyOrElement(registry, part)); |
636 Handle<Object> symbol; | 636 Handle<Object> symbol; |
637 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 637 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
638 isolate, symbol, Object::GetPropertyOrElement(privates, name)); | 638 isolate, symbol, Object::GetPropertyOrElement(privates, name)); |
639 if (!symbol->IsSymbol()) { | 639 if (!symbol->IsSymbol()) { |
640 ASSERT(symbol->IsUndefined()); | 640 ASSERT(symbol->IsUndefined()); |
641 symbol = isolate->factory()->NewPrivateSymbol(); | 641 symbol = isolate->factory()->NewPrivateSymbol(); |
642 Handle<Symbol>::cast(symbol)->set_name(*name); | 642 Handle<Symbol>::cast(symbol)->set_name(*name); |
643 JSObject::SetProperty(Handle<JSObject>::cast(privates), | 643 JSObject::SetProperty(Handle<JSObject>::cast(privates), name, symbol, NONE, |
644 name, symbol, NONE, STRICT).Assert(); | 644 STRICT).Assert(); |
645 } | 645 } |
646 return *symbol; | 646 return *symbol; |
647 } | 647 } |
648 | 648 |
649 | 649 |
650 RUNTIME_FUNCTION(Runtime_NewSymbolWrapper) { | 650 RUNTIME_FUNCTION(Runtime_NewSymbolWrapper) { |
651 HandleScope scope(isolate); | 651 HandleScope scope(isolate); |
652 ASSERT(args.length() == 1); | 652 ASSERT(args.length() == 1); |
653 CONVERT_ARG_HANDLE_CHECKED(Symbol, symbol, 0); | 653 CONVERT_ARG_HANDLE_CHECKED(Symbol, symbol, 0); |
654 return *Object::ToObject(isolate, symbol).ToHandleChecked(); | 654 return *Object::ToObject(isolate, symbol).ToHandleChecked(); |
(...skipping 1441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2096 | 2096 |
2097 static Object* ThrowRedeclarationError(Isolate* isolate, Handle<String> name) { | 2097 static Object* ThrowRedeclarationError(Isolate* isolate, Handle<String> name) { |
2098 HandleScope scope(isolate); | 2098 HandleScope scope(isolate); |
2099 Handle<Object> args[1] = { name }; | 2099 Handle<Object> args[1] = { name }; |
2100 Handle<Object> error = isolate->factory()->NewTypeError( | 2100 Handle<Object> error = isolate->factory()->NewTypeError( |
2101 "var_redeclaration", HandleVector(args, 1)); | 2101 "var_redeclaration", HandleVector(args, 1)); |
2102 return isolate->Throw(*error); | 2102 return isolate->Throw(*error); |
2103 } | 2103 } |
2104 | 2104 |
2105 | 2105 |
2106 // May throw a RedeclarationError. | |
2107 static Object* DeclareGlobals(Isolate* isolate, Handle<GlobalObject> global, | |
2108 Handle<String> name, Handle<Object> value, | |
2109 PropertyAttributes attr, bool is_var, | |
2110 bool is_const, bool is_function) { | |
2111 // Do the lookup own properties only, see ES5 erratum. | |
2112 LookupIterator it(global, name, LookupIterator::CHECK_HIDDEN); | |
2113 PropertyAttributes old_attributes = JSReceiver::GetPropertyAttributes(&it); | |
2114 | |
2115 if (old_attributes != ABSENT) { | |
2116 // The name was declared before; check for conflicting re-declarations. | |
2117 if (is_const) return ThrowRedeclarationError(isolate, name); | |
2118 | |
2119 // Skip var re-declarations. | |
2120 if (is_var) return isolate->heap()->undefined_value(); | |
2121 | |
2122 ASSERT(is_function); | |
2123 if ((old_attributes & DONT_DELETE) != 0) { | |
2124 // Only allow reconfiguring globals to functions in user code (no | |
2125 // natives, which are marked as read-only). | |
2126 ASSERT((attr & READ_ONLY) == 0); | |
2127 | |
2128 // Check whether we can reconfigure the existing property into a | |
2129 // function. | |
2130 PropertyDetails old_details = it.property_details(); | |
2131 // TODO(verwaest): CALLBACKS invalidly includes ExecutableAccessInfo, | |
2132 // which are actually data properties, not accessor properties. | |
2133 if (old_details.IsReadOnly() || old_details.IsDontEnum() || | |
2134 old_details.type() == CALLBACKS) { | |
2135 return ThrowRedeclarationError(isolate, name); | |
2136 } | |
2137 // If the existing property is not configurable, keep its attributes. Do | |
2138 attr = old_attributes; | |
2139 } | |
2140 } | |
2141 | |
2142 // Define or redefine own property. | |
2143 RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes( | |
2144 global, name, value, attr)); | |
2145 | |
2146 return *value; | |
rossberg
2014/07/11 12:54:48
Maybe have a comment saying what this value is use
Toon Verwaest
2014/07/14 07:39:55
Not sure what to say here. It's the result of the
rossberg
2014/07/14 12:04:22
But declarations don't have a result (other than u
| |
2147 } | |
2148 | |
2149 | |
2106 RUNTIME_FUNCTION(Runtime_DeclareGlobals) { | 2150 RUNTIME_FUNCTION(Runtime_DeclareGlobals) { |
2107 HandleScope scope(isolate); | 2151 HandleScope scope(isolate); |
2108 ASSERT(args.length() == 3); | 2152 ASSERT(args.length() == 3); |
2109 Handle<GlobalObject> global(isolate->global_object()); | 2153 Handle<GlobalObject> global(isolate->global_object()); |
2110 | 2154 |
2111 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); | 2155 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); |
2112 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1); | 2156 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1); |
2113 CONVERT_SMI_ARG_CHECKED(flags, 2); | 2157 CONVERT_SMI_ARG_CHECKED(flags, 2); |
2114 | 2158 |
2115 // Traverse the name/value pairs and set the properties. | 2159 // Traverse the name/value pairs and set the properties. |
2116 int length = pairs->length(); | 2160 int length = pairs->length(); |
2117 for (int i = 0; i < length; i += 2) { | 2161 for (int i = 0; i < length; i += 2) { |
2118 HandleScope scope(isolate); | 2162 HandleScope scope(isolate); |
2119 Handle<String> name(String::cast(pairs->get(i))); | 2163 Handle<String> name(String::cast(pairs->get(i))); |
2120 Handle<Object> value(pairs->get(i + 1), isolate); | 2164 Handle<Object> initial_value(pairs->get(i + 1), isolate); |
2121 | 2165 |
2122 // We have to declare a global const property. To capture we only | 2166 // We have to declare a global const property. To capture we only |
2123 // assign to it when evaluating the assignment for "const x = | 2167 // assign to it when evaluating the assignment for "const x = |
2124 // <expr>" the initial value is the hole. | 2168 // <expr>" the initial value is the hole. |
2125 bool is_var = value->IsUndefined(); | 2169 bool is_var = initial_value->IsUndefined(); |
2126 bool is_const = value->IsTheHole(); | 2170 bool is_const = initial_value->IsTheHole(); |
2127 bool is_function = value->IsSharedFunctionInfo(); | 2171 bool is_function = initial_value->IsSharedFunctionInfo(); |
2128 ASSERT(is_var + is_const + is_function == 1); | 2172 ASSERT(is_var + is_const + is_function == 1); |
2129 | 2173 |
2130 if (is_var || is_const) { | 2174 Handle<Object> value; |
2131 // Lookup the property in the global object, and don't set the | 2175 if (is_function) { |
2132 // value of the variable if the property is already there. | |
2133 // Do the lookup own properties only, see ES5 erratum. | |
2134 LookupResult lookup(isolate); | |
2135 global->LookupOwn(name, &lookup, true); | |
2136 if (lookup.IsFound()) { | |
2137 // We found an existing property. Unless it was an interceptor | |
2138 // that claims the property is absent, skip this declaration. | |
2139 if (!lookup.IsInterceptor()) continue; | |
2140 if (JSReceiver::GetPropertyAttributes(global, name) != ABSENT) continue; | |
2141 // Fall-through and introduce the absent property by using | |
2142 // SetProperty. | |
2143 } | |
2144 } else if (is_function) { | |
2145 // Copy the function and update its context. Use it as value. | 2176 // Copy the function and update its context. Use it as value. |
2146 Handle<SharedFunctionInfo> shared = | 2177 Handle<SharedFunctionInfo> shared = |
2147 Handle<SharedFunctionInfo>::cast(value); | 2178 Handle<SharedFunctionInfo>::cast(initial_value); |
2148 Handle<JSFunction> function = | 2179 Handle<JSFunction> function = |
2149 isolate->factory()->NewFunctionFromSharedFunctionInfo( | 2180 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context, |
2150 shared, context, TENURED); | 2181 TENURED); |
2151 value = function; | 2182 value = function; |
2183 } else { | |
2184 value = isolate->factory()->undefined_value(); | |
2152 } | 2185 } |
2153 | 2186 |
2154 LookupResult lookup(isolate); | |
2155 global->LookupOwn(name, &lookup, true); | |
2156 | |
2157 // Compute the property attributes. According to ECMA-262, | 2187 // Compute the property attributes. According to ECMA-262, |
2158 // the property must be non-configurable except in eval. | 2188 // the property must be non-configurable except in eval. |
2189 bool is_native = DeclareGlobalsNativeFlag::decode(flags); | |
2190 bool is_eval = DeclareGlobalsEvalFlag::decode(flags); | |
2159 int attr = NONE; | 2191 int attr = NONE; |
2160 bool is_eval = DeclareGlobalsEvalFlag::decode(flags); | 2192 if (is_const) attr |= READ_ONLY; |
2161 if (!is_eval) { | 2193 if (is_function && is_native) attr |= READ_ONLY; |
2162 attr |= DONT_DELETE; | 2194 if (!is_const && !is_eval) attr |= DONT_DELETE; |
2163 } | |
2164 bool is_native = DeclareGlobalsNativeFlag::decode(flags); | |
2165 if (is_const || (is_native && is_function)) { | |
2166 attr |= READ_ONLY; | |
2167 } | |
2168 | 2195 |
2169 StrictMode strict_mode = DeclareGlobalsStrictMode::decode(flags); | 2196 Object* result = DeclareGlobals(isolate, global, name, value, |
2170 | 2197 static_cast<PropertyAttributes>(attr), |
2171 if (!lookup.IsFound() || is_function) { | 2198 is_var, is_const, is_function); |
2172 // If the own property exists, check that we can reconfigure it | 2199 if (isolate->has_pending_exception()) return result; |
2173 // as required for function declarations. | |
2174 if (lookup.IsFound() && lookup.IsDontDelete()) { | |
2175 if (lookup.IsReadOnly() || lookup.IsDontEnum() || | |
2176 lookup.IsPropertyCallbacks()) { | |
2177 return ThrowRedeclarationError(isolate, name); | |
2178 } | |
2179 // If the existing property is not configurable, keep its attributes. | |
2180 attr = lookup.GetAttributes(); | |
2181 } | |
2182 // Define or redefine own property. | |
2183 RETURN_FAILURE_ON_EXCEPTION(isolate, | |
2184 JSObject::SetOwnPropertyIgnoreAttributes( | |
2185 global, name, value, static_cast<PropertyAttributes>(attr))); | |
2186 } else { | |
2187 // Do a [[Put]] on the existing (own) property. | |
2188 RETURN_FAILURE_ON_EXCEPTION( | |
2189 isolate, | |
2190 JSObject::SetProperty( | |
2191 global, name, value, static_cast<PropertyAttributes>(attr), | |
2192 strict_mode)); | |
2193 } | |
2194 } | |
2195 | |
2196 ASSERT(!isolate->has_pending_exception()); | |
2197 return isolate->heap()->undefined_value(); | |
2198 } | |
2199 | |
2200 | |
2201 RUNTIME_FUNCTION(Runtime_DeclareContextSlot) { | |
2202 HandleScope scope(isolate); | |
2203 ASSERT(args.length() == 4); | |
2204 | |
2205 // Declarations are always made in a function or native context. In the | |
2206 // case of eval code, the context passed is the context of the caller, | |
2207 // which may be some nested context and not the declaration context. | |
2208 CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 0); | |
2209 Handle<Context> context(context_arg->declaration_context()); | |
2210 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); | |
2211 CONVERT_SMI_ARG_CHECKED(mode_arg, 2); | |
2212 PropertyAttributes mode = static_cast<PropertyAttributes>(mode_arg); | |
2213 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE); | |
2214 CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 3); | |
2215 | |
2216 int index; | |
2217 PropertyAttributes attributes; | |
2218 ContextLookupFlags flags = DONT_FOLLOW_CHAINS; | |
2219 BindingFlags binding_flags; | |
2220 Handle<Object> holder = | |
2221 context->Lookup(name, flags, &index, &attributes, &binding_flags); | |
2222 | |
2223 if (attributes != ABSENT) { | |
2224 // The name was declared before; check for conflicting re-declarations. | |
2225 // Note: this is actually inconsistent with what happens for globals (where | |
2226 // we silently ignore such declarations). | |
2227 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) { | |
2228 // Functions are not read-only. | |
2229 ASSERT(mode != READ_ONLY || initial_value->IsTheHole()); | |
2230 return ThrowRedeclarationError(isolate, name); | |
2231 } | |
2232 | |
2233 // Initialize it if necessary. | |
2234 if (*initial_value != NULL) { | |
2235 if (index >= 0) { | |
2236 ASSERT(holder.is_identical_to(context)); | |
2237 if (((attributes & READ_ONLY) == 0) || | |
2238 context->get(index)->IsTheHole()) { | |
2239 context->set(index, *initial_value); | |
2240 } | |
2241 } else { | |
2242 // Slow case: The property is in the context extension object of a | |
2243 // function context or the global object of a native context. | |
2244 Handle<JSObject> object = Handle<JSObject>::cast(holder); | |
2245 RETURN_FAILURE_ON_EXCEPTION( | |
2246 isolate, | |
2247 JSReceiver::SetProperty(object, name, initial_value, mode, SLOPPY)); | |
2248 } | |
2249 } | |
2250 | |
2251 } else { | |
2252 // The property is not in the function context. It needs to be | |
2253 // "declared" in the function context's extension context or as a | |
2254 // property of the the global object. | |
2255 Handle<JSObject> object; | |
2256 if (context->has_extension()) { | |
2257 object = Handle<JSObject>(JSObject::cast(context->extension())); | |
2258 } else { | |
2259 // Context extension objects are allocated lazily. | |
2260 ASSERT(context->IsFunctionContext()); | |
2261 object = isolate->factory()->NewJSObject( | |
2262 isolate->context_extension_function()); | |
2263 context->set_extension(*object); | |
2264 } | |
2265 ASSERT(*object != NULL); | |
2266 | |
2267 // Declare the property by setting it to the initial value if provided, | |
2268 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for | |
2269 // constant declarations). | |
2270 ASSERT(!JSReceiver::HasOwnProperty(object, name)); | |
2271 Handle<Object> value(isolate->heap()->undefined_value(), isolate); | |
2272 if (*initial_value != NULL) value = initial_value; | |
2273 // Declaring a const context slot is a conflicting declaration if | |
2274 // there is a callback with that name in a prototype. It is | |
2275 // allowed to introduce const variables in | |
2276 // JSContextExtensionObjects. They are treated specially in | |
2277 // SetProperty and no setters are invoked for those since they are | |
2278 // not real JSObjects. | |
2279 if (initial_value->IsTheHole() && | |
2280 !object->IsJSContextExtensionObject()) { | |
2281 LookupResult lookup(isolate); | |
2282 object->Lookup(name, &lookup); | |
2283 if (lookup.IsPropertyCallbacks()) { | |
2284 return ThrowRedeclarationError(isolate, name); | |
2285 } | |
2286 } | |
2287 if (object->IsJSGlobalObject()) { | |
2288 // Define own property on the global object. | |
2289 RETURN_FAILURE_ON_EXCEPTION(isolate, | |
2290 JSObject::SetOwnPropertyIgnoreAttributes(object, name, value, mode)); | |
2291 } else { | |
2292 RETURN_FAILURE_ON_EXCEPTION(isolate, | |
2293 JSReceiver::SetProperty(object, name, value, mode, SLOPPY)); | |
2294 } | |
2295 } | 2200 } |
2296 | 2201 |
2297 return isolate->heap()->undefined_value(); | 2202 return isolate->heap()->undefined_value(); |
2298 } | 2203 } |
2299 | 2204 |
2300 | 2205 |
2301 RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) { | 2206 RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) { |
2302 HandleScope scope(isolate); | 2207 HandleScope scope(isolate); |
2303 // args[0] == name | 2208 // args[0] == name |
2304 // args[1] == language_mode | 2209 // args[1] == language_mode |
2305 // args[2] == value (optional) | 2210 // args[2] == value (optional) |
2306 | 2211 |
2307 // Determine if we need to assign to the variable if it already | 2212 // Determine if we need to assign to the variable if it already |
2308 // exists (based on the number of arguments). | 2213 // exists (based on the number of arguments). |
2309 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3); | 2214 RUNTIME_ASSERT(args.length() == 3); |
2310 bool assign = args.length() == 3; | |
2311 | 2215 |
2312 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); | 2216 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); |
2313 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 1); | 2217 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 1); |
2218 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | |
2314 | 2219 |
2315 // According to ECMA-262, section 12.2, page 62, the property must | 2220 Handle<GlobalObject> global(isolate->context()->global_object()); |
2316 // not be deletable. | 2221 Handle<Object> result; |
2317 PropertyAttributes attributes = DONT_DELETE; | 2222 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
2318 | 2223 isolate, result, |
2319 // Lookup the property as own on the global object. If it isn't | 2224 JSReceiver::SetProperty(global, name, value, NONE, strict_mode)); |
2320 // there, there is a property with this name in the prototype chain. | 2225 return *result; |
2321 // We follow Safari and Firefox behavior and only set the property | |
2322 // if there is an explicit initialization value that we have | |
2323 // to assign to the property. | |
2324 // Note that objects can have hidden prototypes, so we need to traverse | |
2325 // the whole chain of hidden prototypes to do an 'own' lookup. | |
2326 LookupResult lookup(isolate); | |
2327 isolate->context()->global_object()->LookupOwn(name, &lookup, true); | |
2328 if (lookup.IsInterceptor()) { | |
2329 Handle<JSObject> holder(lookup.holder()); | |
2330 PropertyAttributes intercepted = | |
2331 JSReceiver::GetPropertyAttributes(holder, name); | |
2332 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { | |
2333 // Found an interceptor that's not read only. | |
2334 if (assign) { | |
2335 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | |
2336 Handle<Object> result; | |
2337 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2338 isolate, result, | |
2339 JSObject::SetPropertyForResult( | |
2340 holder, &lookup, name, value, attributes, strict_mode)); | |
2341 return *result; | |
2342 } else { | |
2343 return isolate->heap()->undefined_value(); | |
2344 } | |
2345 } | |
2346 } | |
2347 | |
2348 if (assign) { | |
2349 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | |
2350 Handle<GlobalObject> global(isolate->context()->global_object()); | |
2351 Handle<Object> result; | |
2352 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2353 isolate, result, | |
2354 JSReceiver::SetProperty(global, name, value, attributes, strict_mode)); | |
2355 return *result; | |
2356 } | |
2357 return isolate->heap()->undefined_value(); | |
2358 } | 2226 } |
2359 | 2227 |
2360 | 2228 |
2361 RUNTIME_FUNCTION(Runtime_InitializeConstGlobal) { | 2229 RUNTIME_FUNCTION(Runtime_InitializeConstGlobal) { |
2362 SealHandleScope shs(isolate); | 2230 HandleScope handle_scope(isolate); |
2363 // All constants are declared with an initial value. The name | 2231 // All constants are declared with an initial value. The name |
2364 // of the constant is the first argument and the initial value | 2232 // of the constant is the first argument and the initial value |
2365 // is the second. | 2233 // is the second. |
2366 RUNTIME_ASSERT(args.length() == 2); | 2234 RUNTIME_ASSERT(args.length() == 2); |
2367 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); | 2235 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); |
2368 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); | 2236 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); |
2369 | 2237 |
2370 // Get the current global object from top. | 2238 Handle<GlobalObject> global = isolate->global_object(); |
2371 GlobalObject* global = isolate->context()->global_object(); | |
2372 | 2239 |
2373 // According to ECMA-262, section 12.2, page 62, the property must | 2240 // Lookup the property as own on the global object. |
2374 // not be deletable. Since it's a const, it must be READ_ONLY too. | 2241 LookupIterator it(global, name, LookupIterator::CHECK_HIDDEN); |
2375 PropertyAttributes attributes = | 2242 PropertyAttributes old_attributes = JSReceiver::GetPropertyAttributes(&it); |
2243 | |
2244 PropertyAttributes attr = | |
2376 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY); | 2245 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY); |
2377 | 2246 // Set the value, but only if we're assigning the initial value to a constant. |
2378 // Lookup the property as own on the global object. If it isn't | 2247 // For now, we determine this by checking if the current value is the hole. |
rossberg
2014/07/11 12:54:49
Update comment?
Toon Verwaest
2014/07/14 07:39:55
Done.
| |
2379 // there, we add the property and take special precautions to always | 2248 // Strict mode handling not needed (const is disallowed in strict mode). |
2380 // add it even in case of callbacks in the prototype chain (this rules | 2249 if (it.IsFound()) { |
2381 // out using SetProperty). We use SetOwnPropertyIgnoreAttributes instead | 2250 // Ignore if we can't reconfigure the value. |
2382 LookupResult lookup(isolate); | 2251 if ((old_attributes & DONT_DELETE) != 0) { |
2383 global->LookupOwn(name, &lookup); | 2252 if ((old_attributes & READ_ONLY) != 0 || |
2384 if (!lookup.IsFound()) { | 2253 it.property_kind() == LookupIterator::ACCESSOR) { |
2385 HandleScope handle_scope(isolate); | 2254 return *value; |
2386 Handle<GlobalObject> global(isolate->context()->global_object()); | 2255 } |
2387 JSObject::AddProperty(global, name, value, attributes); | 2256 attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY); |
2388 return *value; | 2257 } |
2389 } | 2258 } |
2390 | 2259 |
2391 if (!lookup.IsReadOnly()) { | 2260 RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes( |
2392 // Restore global object from context (in case of GC) and continue | 2261 global, name, value, attr)); |
2393 // with setting the value. | |
2394 HandleScope handle_scope(isolate); | |
2395 Handle<GlobalObject> global(isolate->context()->global_object()); | |
2396 | 2262 |
2397 // BUG 1213575: Handle the case where we have to set a read-only | |
2398 // property through an interceptor and only do it if it's | |
2399 // uninitialized, e.g. the hole. Nirk... | |
2400 // Passing sloppy mode because the property is writable. | |
2401 RETURN_FAILURE_ON_EXCEPTION( | |
2402 isolate, | |
2403 JSReceiver::SetProperty(global, name, value, attributes, SLOPPY)); | |
2404 return *value; | |
2405 } | |
2406 | |
2407 // Set the value, but only if we're assigning the initial value to a | |
2408 // constant. For now, we determine this by checking if the | |
2409 // current value is the hole. | |
2410 // Strict mode handling not needed (const is disallowed in strict mode). | |
2411 if (lookup.IsField()) { | |
2412 FixedArray* properties = global->properties(); | |
2413 int index = lookup.GetFieldIndex().outobject_array_index(); | |
2414 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) { | |
2415 properties->set(index, *value); | |
2416 } | |
2417 } else if (lookup.IsNormal()) { | |
2418 if (global->GetNormalizedProperty(&lookup)->IsTheHole() || | |
2419 !lookup.IsReadOnly()) { | |
2420 HandleScope scope(isolate); | |
2421 JSObject::SetNormalizedProperty(Handle<JSObject>(global), &lookup, value); | |
2422 } | |
2423 } else { | |
2424 // Ignore re-initialization of constants that have already been | |
2425 // assigned a constant value. | |
2426 ASSERT(lookup.IsReadOnly() && lookup.IsConstant()); | |
2427 } | |
2428 | |
2429 // Use the set value as the result of the operation. | |
2430 return *value; | 2263 return *value; |
2431 } | 2264 } |
2432 | 2265 |
2433 | 2266 |
2267 RUNTIME_FUNCTION(Runtime_DeclareContextSlot) { | |
rossberg
2014/07/11 12:54:49
Wasn't the plan to rename this to DeclareLookupSlo
Toon Verwaest
2014/07/14 07:39:55
Done.
| |
2268 HandleScope scope(isolate); | |
2269 ASSERT(args.length() == 4); | |
2270 | |
2271 // Declarations are always made in a function or native context. In the case | |
rossberg
2014/07/11 12:54:49
Can also be a global context.
Toon Verwaest
2014/07/14 07:39:55
Done.
| |
2272 // of eval code, the context passed is the context of the caller, which may be | |
2273 // some nested context and not the declaration context. | |
2274 CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 0); | |
2275 Handle<Context> context(context_arg->declaration_context()); | |
2276 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); | |
2277 CONVERT_SMI_ARG_CHECKED(attr_arg, 2); | |
2278 PropertyAttributes attr = static_cast<PropertyAttributes>(attr_arg); | |
2279 RUNTIME_ASSERT(attr == READ_ONLY || attr == NONE); | |
2280 CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 3); | |
2281 | |
2282 bool is_var = *initial_value == NULL; | |
rossberg
2014/07/11 12:54:49
Maybe add a TODO to clean this up also.
Toon Verwaest
2014/07/14 07:39:55
Done.
| |
2283 bool is_const = initial_value->IsTheHole(); | |
2284 bool is_function = initial_value->IsJSFunction(); | |
2285 ASSERT(is_var + is_const + is_function == 1); | |
2286 | |
2287 int index; | |
2288 PropertyAttributes attributes; | |
2289 ContextLookupFlags flags = DONT_FOLLOW_CHAINS; | |
2290 BindingFlags binding_flags; | |
2291 Handle<Object> holder = | |
2292 context->Lookup(name, flags, &index, &attributes, &binding_flags); | |
2293 | |
2294 Handle<JSObject> object; | |
2295 Handle<Object> value = | |
2296 is_function ? initial_value | |
2297 : Handle<Object>::cast(isolate->factory()->undefined_value()); | |
2298 | |
2299 // TODO(verwaest): This case should probably not be covered by this function, | |
2300 // but by DeclareGlobals instead. | |
2301 if ((attributes != ABSENT && holder->IsJSGlobalObject()) || | |
2302 (context_arg->has_extension() && | |
2303 context_arg->extension()->IsJSGlobalObject())) { | |
2304 return DeclareGlobals(isolate, Handle<JSGlobalObject>::cast(holder), name, | |
2305 value, attr, is_var, is_const, is_function); | |
2306 } | |
2307 | |
2308 if (attributes != ABSENT) { | |
2309 // The name was declared before; check for conflicting re-declarations. | |
2310 if (is_const || (attributes & READ_ONLY) != 0) { | |
2311 return ThrowRedeclarationError(isolate, name); | |
2312 } | |
2313 | |
2314 // Skip var re-declarations. | |
2315 if (is_var) return isolate->heap()->undefined_value(); | |
2316 | |
2317 ASSERT(is_function); | |
2318 if (index >= 0) { | |
2319 ASSERT(holder.is_identical_to(context)); | |
2320 context->set(index, *initial_value); | |
2321 return isolate->heap()->undefined_value(); | |
2322 } | |
2323 | |
2324 object = Handle<JSObject>::cast(holder); | |
2325 | |
2326 } else if (context->has_extension()) { | |
2327 object = handle(JSObject::cast(context->extension())); | |
2328 ASSERT(object->IsJSContextExtensionObject() || object->IsJSGlobalObject()); | |
2329 } else { | |
2330 ASSERT(context->IsFunctionContext()); | |
2331 object = | |
2332 isolate->factory()->NewJSObject(isolate->context_extension_function()); | |
2333 context->set_extension(*object); | |
2334 } | |
2335 | |
2336 RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes( | |
2337 object, name, value, attr)); | |
2338 | |
2339 return isolate->heap()->undefined_value(); | |
2340 } | |
2341 | |
2342 | |
2434 RUNTIME_FUNCTION(Runtime_InitializeConstContextSlot) { | 2343 RUNTIME_FUNCTION(Runtime_InitializeConstContextSlot) { |
rossberg
2014/07/11 12:54:49
InitializeLegacyConstLookupSlot?
Toon Verwaest
2014/07/14 07:39:55
Done.
| |
2435 HandleScope scope(isolate); | 2344 HandleScope scope(isolate); |
2436 ASSERT(args.length() == 3); | 2345 ASSERT(args.length() == 3); |
2437 | 2346 |
2438 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); | 2347 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); |
2439 ASSERT(!value->IsTheHole()); | 2348 ASSERT(!value->IsTheHole()); |
2440 // Initializations are always done in a function or native context. | 2349 // Initializations are always done in a function or native context. |
2441 CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 1); | 2350 CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 1); |
2442 Handle<Context> context(context_arg->declaration_context()); | 2351 Handle<Context> context(context_arg->declaration_context()); |
2443 CONVERT_ARG_HANDLE_CHECKED(String, name, 2); | 2352 CONVERT_ARG_HANDLE_CHECKED(String, name, 2); |
2444 | 2353 |
2445 int index; | 2354 int index; |
2446 PropertyAttributes attributes; | 2355 PropertyAttributes attributes; |
2447 ContextLookupFlags flags = FOLLOW_CHAINS; | 2356 ContextLookupFlags flags = DONT_FOLLOW_CHAINS; |
2448 BindingFlags binding_flags; | 2357 BindingFlags binding_flags; |
2449 Handle<Object> holder = | 2358 Handle<Object> holder = |
2450 context->Lookup(name, flags, &index, &attributes, &binding_flags); | 2359 context->Lookup(name, flags, &index, &attributes, &binding_flags); |
2451 | 2360 |
2452 if (index >= 0) { | 2361 if (index >= 0) { |
2453 ASSERT(holder->IsContext()); | 2362 ASSERT(holder->IsContext()); |
2454 // Property was found in a context. Perform the assignment if we | 2363 // Property was found in a context. Perform the assignment if the constant |
2455 // found some non-constant or an uninitialized constant. | 2364 // was uninitialized. |
2456 Handle<Context> context = Handle<Context>::cast(holder); | 2365 Handle<Context> context = Handle<Context>::cast(holder); |
2457 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) { | 2366 ASSERT((attributes & READ_ONLY) != 0); |
2458 context->set(index, *value); | 2367 if (context->get(index)->IsTheHole()) context->set(index, *value); |
2459 } | |
2460 return *value; | 2368 return *value; |
2461 } | 2369 } |
2462 | 2370 |
2463 // The property could not be found, we introduce it as a property of the | 2371 PropertyAttributes attr = |
2464 // global object. | 2372 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY); |
2373 | |
2374 // Strict mode handling not needed (const is disallowed in strict mode). | |
rossberg
2014/07/11 12:54:48
s/const/legacy const/
Toon Verwaest
2014/07/14 07:39:55
Done.
| |
2375 | |
2376 // The declared const was configurable, and may have been deleted in the | |
2377 // meanwhile. If so, re-introduce the variable in the context extension. | |
2378 ASSERT(context_arg->has_extension()); | |
2465 if (attributes == ABSENT) { | 2379 if (attributes == ABSENT) { |
2466 Handle<JSObject> global = Handle<JSObject>( | 2380 holder = handle(context_arg->extension(), isolate); |
2467 isolate->context()->global_object()); | 2381 } else { |
2468 // Strict mode not needed (const disallowed in strict mode). | 2382 // For JSContextExtensionObjects, the initializer can be run multiple times |
2469 RETURN_FAILURE_ON_EXCEPTION( | 2383 // if in a for loop: for (var i = 0; i < 2; i++) { const x = i; }. Only the |
2470 isolate, | 2384 // first assignment should go through. For JSGlobalObjects, additionally any |
2471 JSReceiver::SetProperty(global, name, value, NONE, SLOPPY)); | 2385 // code can run in between that modifies the declared property. |
2472 return *value; | 2386 ASSERT(holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject()); |
2387 | |
2388 LookupIterator it(holder, name, LookupIterator::CHECK_HIDDEN); | |
2389 PropertyAttributes old_attributes = JSReceiver::GetPropertyAttributes(&it); | |
2390 | |
2391 // Ignore if we can't reconfigure the value. | |
2392 if ((old_attributes & DONT_DELETE) != 0) { | |
2393 if ((old_attributes & READ_ONLY) != 0 || | |
2394 it.property_kind() == LookupIterator::ACCESSOR) { | |
2395 return *value; | |
2396 } | |
2397 attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY); | |
2398 } | |
2473 } | 2399 } |
2474 | 2400 |
2475 // The property was present in some function's context extension object, | 2401 RETURN_FAILURE_ON_EXCEPTION( |
2476 // as a property on the subject of a with, or as a property of the global | 2402 isolate, JSObject::SetOwnPropertyIgnoreAttributes( |
2477 // object. | 2403 Handle<JSObject>::cast(holder), name, value, attr)); |
2478 // | |
2479 // In most situations, eval-introduced consts should still be present in | |
2480 // the context extension object. However, because declaration and | |
2481 // initialization are separate, the property might have been deleted | |
2482 // before we reach the initialization point. | |
2483 // | |
2484 // Example: | |
2485 // | |
2486 // function f() { eval("delete x; const x;"); } | |
2487 // | |
2488 // In that case, the initialization behaves like a normal assignment. | |
2489 Handle<JSObject> object = Handle<JSObject>::cast(holder); | |
2490 | |
2491 if (*object == context->extension()) { | |
2492 // This is the property that was introduced by the const declaration. | |
2493 // Set it if it hasn't been set before. NOTE: We cannot use | |
2494 // GetProperty() to get the current value as it 'unholes' the value. | |
2495 LookupResult lookup(isolate); | |
2496 object->LookupOwnRealNamedProperty(name, &lookup); | |
2497 ASSERT(lookup.IsFound()); // the property was declared | |
2498 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only | |
2499 | |
2500 if (lookup.IsField()) { | |
2501 FixedArray* properties = object->properties(); | |
2502 FieldIndex index = lookup.GetFieldIndex(); | |
2503 ASSERT(!index.is_inobject()); | |
2504 if (properties->get(index.outobject_array_index())->IsTheHole()) { | |
2505 properties->set(index.outobject_array_index(), *value); | |
2506 } | |
2507 } else if (lookup.IsNormal()) { | |
2508 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) { | |
2509 JSObject::SetNormalizedProperty(object, &lookup, value); | |
2510 } | |
2511 } else { | |
2512 // We should not reach here. Any real, named property should be | |
2513 // either a field or a dictionary slot. | |
2514 UNREACHABLE(); | |
2515 } | |
2516 } else { | |
2517 // The property was found on some other object. Set it if it is not a | |
2518 // read-only property. | |
2519 if ((attributes & READ_ONLY) == 0) { | |
2520 // Strict mode not needed (const disallowed in strict mode). | |
2521 RETURN_FAILURE_ON_EXCEPTION( | |
2522 isolate, | |
2523 JSReceiver::SetProperty(object, name, value, attributes, SLOPPY)); | |
2524 } | |
2525 } | |
2526 | 2404 |
2527 return *value; | 2405 return *value; |
2528 } | 2406 } |
2529 | 2407 |
2530 | 2408 |
2531 RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) { | 2409 RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) { |
2532 HandleScope scope(isolate); | 2410 HandleScope scope(isolate); |
2533 ASSERT(args.length() == 2); | 2411 ASSERT(args.length() == 2); |
2534 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | 2412 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
2535 CONVERT_SMI_ARG_CHECKED(properties, 1); | 2413 CONVERT_SMI_ARG_CHECKED(properties, 1); |
(...skipping 6779 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9315 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadContextSlot) { | 9193 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadContextSlot) { |
9316 return LoadContextSlotHelper(args, isolate, true); | 9194 return LoadContextSlotHelper(args, isolate, true); |
9317 } | 9195 } |
9318 | 9196 |
9319 | 9197 |
9320 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadContextSlotNoReferenceError) { | 9198 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadContextSlotNoReferenceError) { |
9321 return LoadContextSlotHelper(args, isolate, false); | 9199 return LoadContextSlotHelper(args, isolate, false); |
9322 } | 9200 } |
9323 | 9201 |
9324 | 9202 |
9325 RUNTIME_FUNCTION(Runtime_StoreContextSlot) { | 9203 RUNTIME_FUNCTION(Runtime_StoreLookupSlot) { |
9326 HandleScope scope(isolate); | 9204 HandleScope scope(isolate); |
9327 ASSERT(args.length() == 4); | 9205 ASSERT(args.length() == 4); |
9328 | 9206 |
9329 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); | 9207 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); |
9330 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1); | 9208 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1); |
9331 CONVERT_ARG_HANDLE_CHECKED(String, name, 2); | 9209 CONVERT_ARG_HANDLE_CHECKED(String, name, 2); |
9332 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 3); | 9210 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 3); |
9333 | 9211 |
9334 int index; | 9212 int index; |
9335 PropertyAttributes attributes; | 9213 PropertyAttributes attributes; |
9336 ContextLookupFlags flags = FOLLOW_CHAINS; | 9214 ContextLookupFlags flags = FOLLOW_CHAINS; |
9337 BindingFlags binding_flags; | 9215 BindingFlags binding_flags; |
9338 Handle<Object> holder = context->Lookup(name, | 9216 Handle<Object> holder = context->Lookup(name, |
9339 flags, | 9217 flags, |
9340 &index, | 9218 &index, |
9341 &attributes, | 9219 &attributes, |
9342 &binding_flags); | 9220 &binding_flags); |
9221 // In case of JSProxy, an exception might have been thrown. | |
9343 if (isolate->has_pending_exception()) return isolate->heap()->exception(); | 9222 if (isolate->has_pending_exception()) return isolate->heap()->exception(); |
9344 | 9223 |
9224 // The property was found in a context slot. | |
9345 if (index >= 0) { | 9225 if (index >= 0) { |
9346 // The property was found in a context slot. | |
9347 Handle<Context> context = Handle<Context>::cast(holder); | |
9348 if (binding_flags == MUTABLE_CHECK_INITIALIZED && | |
9349 context->get(index)->IsTheHole()) { | |
9350 Handle<Object> error = | |
9351 isolate->factory()->NewReferenceError("not_defined", | |
9352 HandleVector(&name, 1)); | |
9353 return isolate->Throw(*error); | |
9354 } | |
9355 // Ignore if read_only variable. | |
9356 if ((attributes & READ_ONLY) == 0) { | 9226 if ((attributes & READ_ONLY) == 0) { |
9357 // Context is a fixed array and set cannot fail. | 9227 Handle<Context>::cast(holder)->set(index, *value); |
9358 context->set(index, *value); | |
9359 } else if (strict_mode == STRICT) { | 9228 } else if (strict_mode == STRICT) { |
9360 // Setting read only property in strict mode. | 9229 // Setting read only property in strict mode. |
9361 Handle<Object> error = | 9230 Handle<Object> error = |
9362 isolate->factory()->NewTypeError("strict_cannot_assign", | 9231 isolate->factory()->NewTypeError("strict_cannot_assign", |
9363 HandleVector(&name, 1)); | 9232 HandleVector(&name, 1)); |
9364 return isolate->Throw(*error); | 9233 return isolate->Throw(*error); |
9365 } | 9234 } |
9366 return *value; | 9235 return *value; |
9367 } | 9236 } |
9368 | 9237 |
9369 // Slow case: The property is not in a context slot. It is either in a | 9238 // Slow case: The property is not in a context slot. It is either in a |
9370 // context extension object, a property of the subject of a with, or a | 9239 // context extension object, a property of the subject of a with, or a |
9371 // property of the global object. | 9240 // property of the global object. |
9372 Handle<JSReceiver> object; | 9241 Handle<JSReceiver> object; |
9373 | 9242 if (attributes != ABSENT) { |
9374 if (!holder.is_null()) { | |
9375 // The property exists on the holder. | 9243 // The property exists on the holder. |
9376 object = Handle<JSReceiver>::cast(holder); | 9244 object = Handle<JSReceiver>::cast(holder); |
9245 } else if (strict_mode == STRICT) { | |
9246 // If absent in strict mode: throw. | |
9247 Handle<Object> error = isolate->factory()->NewReferenceError( | |
9248 "not_defined", HandleVector(&name, 1)); | |
9249 return isolate->Throw(*error); | |
9377 } else { | 9250 } else { |
9378 // The property was not found. | 9251 // If absent in sloppy mode: add the property to the global object. |
9379 ASSERT(attributes == ABSENT); | 9252 object = Handle<JSReceiver>(context->global_object()); |
9380 | |
9381 if (strict_mode == STRICT) { | |
9382 // Throw in strict mode (assignment to undefined variable). | |
9383 Handle<Object> error = | |
9384 isolate->factory()->NewReferenceError( | |
9385 "not_defined", HandleVector(&name, 1)); | |
9386 return isolate->Throw(*error); | |
9387 } | |
9388 // In sloppy mode, the property is added to the global object. | |
9389 attributes = NONE; | |
9390 object = Handle<JSReceiver>(isolate->context()->global_object()); | |
9391 } | 9253 } |
9392 | 9254 |
9393 // Set the property if it's not read only or doesn't yet exist. | 9255 RETURN_FAILURE_ON_EXCEPTION( |
9394 if ((attributes & READ_ONLY) == 0 || | 9256 isolate, JSReceiver::SetProperty(object, name, value, NONE, strict_mode)); |
9395 (JSReceiver::GetOwnPropertyAttributes(object, name) == ABSENT)) { | 9257 |
9396 RETURN_FAILURE_ON_EXCEPTION( | |
9397 isolate, | |
9398 JSReceiver::SetProperty(object, name, value, NONE, strict_mode)); | |
9399 } else if (strict_mode == STRICT && (attributes & READ_ONLY) != 0) { | |
9400 // Setting read only property in strict mode. | |
9401 Handle<Object> error = | |
9402 isolate->factory()->NewTypeError( | |
9403 "strict_cannot_assign", HandleVector(&name, 1)); | |
9404 return isolate->Throw(*error); | |
9405 } | |
9406 return *value; | 9258 return *value; |
9407 } | 9259 } |
9408 | 9260 |
9409 | 9261 |
9410 RUNTIME_FUNCTION(Runtime_Throw) { | 9262 RUNTIME_FUNCTION(Runtime_Throw) { |
9411 HandleScope scope(isolate); | 9263 HandleScope scope(isolate); |
9412 ASSERT(args.length() == 1); | 9264 ASSERT(args.length() == 1); |
9413 | 9265 |
9414 return isolate->Throw(args[0]); | 9266 return isolate->Throw(args[0]); |
9415 } | 9267 } |
(...skipping 5689 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
15105 } | 14957 } |
15106 return NULL; | 14958 return NULL; |
15107 } | 14959 } |
15108 | 14960 |
15109 | 14961 |
15110 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) { | 14962 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) { |
15111 return &(kIntrinsicFunctions[static_cast<int>(id)]); | 14963 return &(kIntrinsicFunctions[static_cast<int>(id)]); |
15112 } | 14964 } |
15113 | 14965 |
15114 } } // namespace v8::internal | 14966 } } // namespace v8::internal |
OLD | NEW |