| Index: src/ic.cc
|
| ===================================================================
|
| --- src/ic.cc (revision 7031)
|
| +++ src/ic.cc (working copy)
|
| @@ -349,7 +349,10 @@
|
| void StoreIC::Clear(Address address, Code* target) {
|
| if (target->ic_state() == UNINITIALIZED) return;
|
| ClearInlinedVersion(address);
|
| - SetTargetAtAddress(address, initialize_stub());
|
| + SetTargetAtAddress(address,
|
| + (target->extra_ic_state() == kStrictMode)
|
| + ? initialize_stub_strict()
|
| + : initialize_stub());
|
| }
|
|
|
|
|
| @@ -370,7 +373,10 @@
|
|
|
| void KeyedStoreIC::Clear(Address address, Code* target) {
|
| if (target->ic_state() == UNINITIALIZED) return;
|
| - SetTargetAtAddress(address, initialize_stub());
|
| + SetTargetAtAddress(address,
|
| + (target->extra_ic_state() == kStrictMode)
|
| + ? initialize_stub_strict()
|
| + : initialize_stub());
|
| }
|
|
|
|
|
| @@ -439,16 +445,25 @@
|
| }
|
|
|
|
|
| -void CallICBase::ReceiverToObject(Handle<Object> object) {
|
| - HandleScope scope(isolate());
|
| - Handle<Object> receiver = object;
|
| +void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee,
|
| + Handle<Object> object) {
|
| + if (callee->IsJSFunction()) {
|
| + Handle<JSFunction> function = Handle<JSFunction>::cast(callee);
|
| + if (function->shared()->strict_mode() || function->IsBuiltin()) {
|
| + // Do not wrap receiver for strict mode functions or for builtins.
|
| + return;
|
| + }
|
| + }
|
|
|
| - // Change the receiver to the result of calling ToObject on it.
|
| - const int argc = this->target()->arguments_count();
|
| - StackFrameLocator locator;
|
| - JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
|
| - int index = frame->ComputeExpressionsCount() - (argc + 1);
|
| - frame->SetExpression(index, *isolate()->factory()->ToObject(object));
|
| + // And only wrap string, number or boolean.
|
| + if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
|
| + // Change the receiver to the result of calling ToObject on it.
|
| + const int argc = this->target()->arguments_count();
|
| + StackFrameLocator locator;
|
| + JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
|
| + int index = frame->ComputeExpressionsCount() - (argc + 1);
|
| + frame->SetExpression(index, *isolate()->factory()->ToObject(object));
|
| + }
|
| }
|
|
|
|
|
| @@ -462,10 +477,6 @@
|
| return TypeError("non_object_property_call", object, name);
|
| }
|
|
|
| - if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
|
| - ReceiverToObject(object);
|
| - }
|
| -
|
| // Check if the name is trivially convertible to an index and get
|
| // the element if so.
|
| uint32_t index;
|
| @@ -509,6 +520,7 @@
|
| object->GetProperty(*object, &lookup, *name, &attr);
|
| if (!maybe_result->ToObject(&result)) return maybe_result;
|
| }
|
| +
|
| if (lookup.type() == INTERCEPTOR) {
|
| // If the object does not have the requested property, check which
|
| // exception we need to throw.
|
| @@ -520,32 +532,38 @@
|
| }
|
| }
|
|
|
| - ASSERT(result != isolate()->heap()->the_hole_value());
|
| + ASSERT(!result->IsTheHole());
|
|
|
| - if (result->IsJSFunction()) {
|
| + HandleScope scope(isolate());
|
| + // Wrap result in a handle because ReceiverToObjectIfRequired may allocate
|
| + // new object and cause GC.
|
| + Handle<Object> result_handle(result);
|
| + // Make receiver an object if the callee requires it. Strict mode or builtin
|
| + // functions do not wrap the receiver, non-strict functions and objects
|
| + // called as functions do.
|
| + ReceiverToObjectIfRequired(result_handle, object);
|
| +
|
| + if (result_handle->IsJSFunction()) {
|
| #ifdef ENABLE_DEBUGGER_SUPPORT
|
| // Handle stepping into a function if step into is active.
|
| Debug* debug = isolate()->debug();
|
| if (debug->StepInActive()) {
|
| // Protect the result in a handle as the debugger can allocate and might
|
| // cause GC.
|
| - HandleScope scope(isolate());
|
| - Handle<JSFunction> function(JSFunction::cast(result), isolate());
|
| + Handle<JSFunction> function(JSFunction::cast(*result_handle), isolate());
|
| debug->HandleStepIn(function, object, fp(), false);
|
| return *function;
|
| }
|
| #endif
|
|
|
| - return result;
|
| + return *result_handle;
|
| }
|
|
|
| // Try to find a suitable function delegate for the object at hand.
|
| - result = TryCallAsFunction(result);
|
| - MaybeObject* answer = result;
|
| - if (!result->IsJSFunction()) {
|
| - answer = TypeError("property_not_function", object, name);
|
| - }
|
| - return answer;
|
| + result_handle = Handle<Object>(TryCallAsFunction(*result_handle));
|
| + if (result_handle->IsJSFunction()) return *result_handle;
|
| +
|
| + return TypeError("property_not_function", object, name);
|
| }
|
|
|
|
|
| @@ -570,8 +588,8 @@
|
| case kStringCharAt:
|
| if (object->IsString()) {
|
| String* string = String::cast(*object);
|
| - // Check that there's the right wrapper in the receiver slot.
|
| - ASSERT(string == JSValue::cast(args[0])->value());
|
| + // Check there's the right string value or wrapper in the receiver slot.
|
| + ASSERT(string == args[0] || string == JSValue::cast(args[0])->value());
|
| // If we're in the default (fastest) state and the index is
|
| // out of bounds, update the state to record this fact.
|
| if (*extra_ic_state == DEFAULT_STRING_STUB &&
|
| @@ -787,10 +805,6 @@
|
| return TypeError("non_object_property_call", object, key);
|
| }
|
|
|
| - if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
|
| - ReceiverToObject(object);
|
| - }
|
| -
|
| if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) {
|
| int argc = target()->arguments_count();
|
| InLoopFlag in_loop = target()->ic_in_loop();
|
| @@ -805,19 +819,21 @@
|
| #endif
|
| }
|
| }
|
| - Object* result;
|
| - { MaybeObject* maybe_result = Runtime::GetObjectProperty(isolate(),
|
| - object,
|
| - key);
|
| - if (!maybe_result->ToObject(&result)) return maybe_result;
|
| - }
|
| - if (result->IsJSFunction()) return result;
|
| - result = TryCallAsFunction(result);
|
| - MaybeObject* answer = result;
|
| - if (!result->IsJSFunction()) {
|
| - answer = TypeError("property_not_function", object, key);
|
| - }
|
| - return answer;
|
| +
|
| + HandleScope scope(isolate());
|
| + Handle<Object> result = GetProperty(object, key);
|
| + RETURN_IF_EMPTY_HANDLE(isolate(), result);
|
| +
|
| + // Make receiver an object if the callee requires it. Strict mode or builtin
|
| + // functions do not wrap the receiver, non-strict functions and objects
|
| + // called as functions do.
|
| + ReceiverToObjectIfRequired(result, object);
|
| +
|
| + if (result->IsJSFunction()) return *result;
|
| + result = Handle<Object>(TryCallAsFunction(*result));
|
| + if (result->IsJSFunction()) return *result;
|
| +
|
| + return TypeError("property_not_function", object, key);
|
| }
|
|
|
|
|
| @@ -1246,7 +1262,7 @@
|
| if (receiver->HasExternalArrayElements()) {
|
| MaybeObject* probe =
|
| isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
|
| - *receiver, false);
|
| + *receiver, false, kNonStrictMode);
|
| stub = probe->IsFailure() ?
|
| NULL : Code::cast(probe->ToObjectUnchecked());
|
| } else if (receiver->HasIndexedInterceptor()) {
|
| @@ -1397,6 +1413,7 @@
|
|
|
|
|
| MaybeObject* StoreIC::Store(State state,
|
| + StrictModeFlag strict_mode,
|
| Handle<Object> object,
|
| Handle<String> name,
|
| Handle<Object> value) {
|
| @@ -1426,10 +1443,11 @@
|
| #ifdef DEBUG
|
| if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n");
|
| #endif
|
| - Code* target = isolate()->builtins()->builtin(
|
| - Builtins::StoreIC_ArrayLength);
|
| - set_target(target);
|
| - return receiver->SetProperty(*name, *value, NONE);
|
| + Builtins::Name target = (strict_mode == kStrictMode)
|
| + ? Builtins::StoreIC_ArrayLength_Strict
|
| + : Builtins::StoreIC_ArrayLength;
|
| + set_target(isolate()->builtins()->builtin(target));
|
| + return receiver->SetProperty(*name, *value, NONE, strict_mode);
|
| }
|
|
|
| // Lookup the property locally in the receiver.
|
| @@ -1453,13 +1471,15 @@
|
| // Index is an offset from the end of the object.
|
| int offset = map->instance_size() + (index * kPointerSize);
|
| if (PatchInlinedStore(address(), map, offset)) {
|
| - set_target(megamorphic_stub());
|
| + set_target((strict_mode == kStrictMode)
|
| + ? megamorphic_stub_strict()
|
| + : megamorphic_stub());
|
| #ifdef DEBUG
|
| if (FLAG_trace_ic) {
|
| PrintF("[StoreIC : inline patch %s]\n", *name->ToCString());
|
| }
|
| #endif
|
| - return receiver->SetProperty(*name, *value, NONE);
|
| + return receiver->SetProperty(*name, *value, NONE, strict_mode);
|
| #ifdef DEBUG
|
|
|
| } else {
|
| @@ -1486,15 +1506,28 @@
|
|
|
| // If no inlined store ic was patched, generate a stub for this
|
| // store.
|
| - UpdateCaches(&lookup, state, receiver, name, value);
|
| + UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
|
| + } else {
|
| + // Strict mode doesn't allow setting non-existent global property
|
| + // or an assignment to a read only property.
|
| + if (strict_mode == kStrictMode) {
|
| + if (lookup.IsFound() && lookup.IsReadOnly()) {
|
| + return TypeError("strict_read_only_property", object, name);
|
| + } else if (IsContextual(object)) {
|
| + return ReferenceError("not_defined", name);
|
| + }
|
| + }
|
| }
|
| }
|
|
|
| if (receiver->IsJSGlobalProxy()) {
|
| // Generate a generic stub that goes to the runtime when we see a global
|
| // proxy as receiver.
|
| - if (target() != global_proxy_stub()) {
|
| - set_target(global_proxy_stub());
|
| + Code* stub = (strict_mode == kStrictMode)
|
| + ? global_proxy_stub_strict()
|
| + : global_proxy_stub();
|
| + if (target() != stub) {
|
| + set_target(stub);
|
| #ifdef DEBUG
|
| TraceIC("StoreIC", name, state, target());
|
| #endif
|
| @@ -1502,12 +1535,13 @@
|
| }
|
|
|
| // Set the property.
|
| - return receiver->SetProperty(*name, *value, NONE);
|
| + return receiver->SetProperty(*name, *value, NONE, strict_mode);
|
| }
|
|
|
|
|
| void StoreIC::UpdateCaches(LookupResult* lookup,
|
| State state,
|
| + StrictModeFlag strict_mode,
|
| Handle<JSObject> receiver,
|
| Handle<String> name,
|
| Handle<Object> value) {
|
| @@ -1529,7 +1563,7 @@
|
| switch (type) {
|
| case FIELD: {
|
| maybe_code = isolate()->stub_cache()->ComputeStoreField(
|
| - *name, *receiver, lookup->GetFieldIndex());
|
| + *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode);
|
| break;
|
| }
|
| case MAP_TRANSITION: {
|
| @@ -1539,7 +1573,7 @@
|
| Handle<Map> transition(lookup->GetTransitionMap());
|
| int index = transition->PropertyIndexFor(*name);
|
| maybe_code = isolate()->stub_cache()->ComputeStoreField(
|
| - *name, *receiver, index, *transition);
|
| + *name, *receiver, index, *transition, strict_mode);
|
| break;
|
| }
|
| case NORMAL: {
|
| @@ -1551,10 +1585,10 @@
|
| JSGlobalPropertyCell* cell =
|
| JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
|
| maybe_code = isolate()->stub_cache()->ComputeStoreGlobal(
|
| - *name, *global, cell);
|
| + *name, *global, cell, strict_mode);
|
| } else {
|
| if (lookup->holder() != *receiver) return;
|
| - maybe_code = isolate()->stub_cache()->ComputeStoreNormal();
|
| + maybe_code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
|
| }
|
| break;
|
| }
|
| @@ -1562,15 +1596,14 @@
|
| if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
|
| AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
|
| if (v8::ToCData<Address>(callback->setter()) == 0) return;
|
| - maybe_code = isolate()->stub_cache()->ComputeStoreCallback(*name,
|
| - *receiver,
|
| - callback);
|
| + maybe_code = isolate()->stub_cache()->ComputeStoreCallback(
|
| + *name, *receiver, callback, strict_mode);
|
| break;
|
| }
|
| case INTERCEPTOR: {
|
| ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined());
|
| - maybe_code = isolate()->stub_cache()->ComputeStoreInterceptor(*name,
|
| - *receiver);
|
| + maybe_code = isolate()->stub_cache()->ComputeStoreInterceptor(
|
| + *name, *receiver, strict_mode);
|
| break;
|
| }
|
| default:
|
| @@ -1586,7 +1619,11 @@
|
| set_target(Code::cast(code));
|
| } else if (state == MONOMORPHIC) {
|
| // Only move to megamorphic if the target changes.
|
| - if (target() != Code::cast(code)) set_target(megamorphic_stub());
|
| + if (target() != Code::cast(code)) {
|
| + set_target((strict_mode == kStrictMode)
|
| + ? megamorphic_stub_strict()
|
| + : megamorphic_stub());
|
| + }
|
| } else if (state == MEGAMORPHIC) {
|
| // Update the stub cache.
|
| isolate()->stub_cache()->Set(*name,
|
| @@ -1601,6 +1638,7 @@
|
|
|
|
|
| MaybeObject* KeyedStoreIC::Store(State state,
|
| + StrictModeFlag strict_mode,
|
| Handle<Object> object,
|
| Handle<Object> key,
|
| Handle<Object> value) {
|
| @@ -1632,11 +1670,11 @@
|
|
|
| // Update inline cache and stub cache.
|
| if (FLAG_use_ic) {
|
| - UpdateCaches(&lookup, state, receiver, name, value);
|
| + UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
|
| }
|
|
|
| // Set the property.
|
| - return receiver->SetProperty(*name, *value, NONE);
|
| + return receiver->SetProperty(*name, *value, NONE, strict_mode);
|
| }
|
|
|
| // Do not use ICs for objects that require access checks (including
|
| @@ -1645,34 +1683,44 @@
|
| ASSERT(!(use_ic && object->IsJSGlobalProxy()));
|
|
|
| if (use_ic) {
|
| - Code* stub = generic_stub();
|
| - if (object->IsJSObject()) {
|
| - Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
| - if (receiver->HasExternalArrayElements()) {
|
| - MaybeObject* probe =
|
| - isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
|
| - *receiver, true);
|
| - stub =
|
| - probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked());
|
| - } else if (state == UNINITIALIZED &&
|
| - key->IsSmi() &&
|
| - receiver->map()->has_fast_elements()) {
|
| - MaybeObject* probe =
|
| - isolate()->stub_cache()->ComputeKeyedStoreSpecialized(*receiver);
|
| - stub =
|
| - probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked());
|
| + Code* stub =
|
| + (strict_mode == kStrictMode) ? generic_stub_strict() : generic_stub();
|
| + if (state == UNINITIALIZED) {
|
| + if (object->IsJSObject()) {
|
| + Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
| + if (receiver->HasExternalArrayElements()) {
|
| + MaybeObject* probe =
|
| + isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
|
| + *receiver, true, strict_mode);
|
| + stub = probe->IsFailure() ?
|
| + NULL : Code::cast(probe->ToObjectUnchecked());
|
| + } else if (receiver->HasPixelElements()) {
|
| + MaybeObject* probe =
|
| + isolate()->stub_cache()->ComputeKeyedStorePixelArray(
|
| + *receiver, strict_mode);
|
| + stub = probe->IsFailure() ?
|
| + NULL : Code::cast(probe->ToObjectUnchecked());
|
| + } else if (key->IsSmi() && receiver->map()->has_fast_elements()) {
|
| + MaybeObject* probe =
|
| + isolate()->stub_cache()->ComputeKeyedStoreSpecialized(
|
| + *receiver, strict_mode);
|
| + stub = probe->IsFailure() ?
|
| + NULL : Code::cast(probe->ToObjectUnchecked());
|
| + }
|
| }
|
| }
|
| if (stub != NULL) set_target(stub);
|
| }
|
|
|
| // Set the property.
|
| - return Runtime::SetObjectProperty(isolate(), object, key, value, NONE);
|
| + return Runtime::SetObjectProperty(
|
| + isolate(), object , key, value, NONE, strict_mode);
|
| }
|
|
|
|
|
| void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
|
| State state,
|
| + StrictModeFlag strict_mode,
|
| Handle<JSObject> receiver,
|
| Handle<String> name,
|
| Handle<Object> value) {
|
| @@ -1700,7 +1748,7 @@
|
| switch (type) {
|
| case FIELD: {
|
| maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField(
|
| - *name, *receiver, lookup->GetFieldIndex());
|
| + *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode);
|
| break;
|
| }
|
| case MAP_TRANSITION: {
|
| @@ -1710,7 +1758,7 @@
|
| Handle<Map> transition(lookup->GetTransitionMap());
|
| int index = transition->PropertyIndexFor(*name);
|
| maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField(
|
| - *name, *receiver, index, *transition);
|
| + *name, *receiver, index, *transition, strict_mode);
|
| break;
|
| }
|
| // fall through.
|
| @@ -1718,7 +1766,9 @@
|
| default: {
|
| // Always rewrite to the generic case so that we do not
|
| // repeatedly try to rewrite.
|
| - maybe_code = generic_stub();
|
| + maybe_code = (strict_mode == kStrictMode)
|
| + ? generic_stub_strict()
|
| + : generic_stub();
|
| break;
|
| }
|
| }
|
| @@ -1733,7 +1783,9 @@
|
| if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
|
| set_target(Code::cast(code));
|
| } else if (state == MONOMORPHIC) {
|
| - set_target(megamorphic_stub());
|
| + set_target((strict_mode == kStrictMode)
|
| + ? megamorphic_stub_strict()
|
| + : megamorphic_stub());
|
| }
|
|
|
| #ifdef DEBUG
|
| @@ -1843,7 +1895,11 @@
|
| ASSERT(args.length() == 3);
|
| StoreIC ic(isolate);
|
| IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
|
| - return ic.Store(state, args.at<Object>(0), args.at<String>(1),
|
| + Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
|
| + return ic.Store(state,
|
| + static_cast<StrictModeFlag>(extra_ic_state & kStrictMode),
|
| + args.at<Object>(0),
|
| + args.at<String>(1),
|
| args.at<Object>(2));
|
| }
|
|
|
| @@ -1912,7 +1968,11 @@
|
| ASSERT(args.length() == 3);
|
| KeyedStoreIC ic(isolate);
|
| IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
|
| - return ic.Store(state, args.at<Object>(0), args.at<Object>(1),
|
| + Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
|
| + return ic.Store(state,
|
| + static_cast<StrictModeFlag>(extra_ic_state & kStrictMode),
|
| + args.at<Object>(0),
|
| + args.at<Object>(1),
|
| args.at<Object>(2));
|
| }
|
|
|
|
|