diff options
Diffstat (limited to 'chromium/v8/src/runtime.cc')
-rw-r--r-- | chromium/v8/src/runtime.cc | 7458 |
1 files changed, 3875 insertions, 3583 deletions
diff --git a/chromium/v8/src/runtime.cc b/chromium/v8/src/runtime.cc index 8333380e83b..36b3177b7c0 100644 --- a/chromium/v8/src/runtime.cc +++ b/chromium/v8/src/runtime.cc @@ -1,74 +1,51 @@ // Copyright 2012 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. #include <stdlib.h> #include <limits> -#include "v8.h" - -#include "accessors.h" -#include "allocation-site-scopes.h" -#include "api.h" -#include "arguments.h" -#include "bootstrapper.h" -#include "codegen.h" -#include "compilation-cache.h" -#include "compiler.h" -#include "cpu.h" -#include "cpu-profiler.h" -#include "dateparser-inl.h" -#include "debug.h" -#include "deoptimizer.h" -#include "date.h" -#include "execution.h" -#include "full-codegen.h" -#include "global-handles.h" -#include "isolate-inl.h" -#include "jsregexp.h" -#include "jsregexp-inl.h" -#include "json-parser.h" -#include "json-stringifier.h" -#include "liveedit.h" -#include "misc-intrinsics.h" -#include "parser.h" -#include "platform.h" -#include "runtime-profiler.h" -#include "runtime.h" -#include "scopeinfo.h" -#include "smart-pointers.h" -#include "string-search.h" -#include "stub-cache.h" -#include "uri.h" -#include "v8conversions.h" -#include "v8threads.h" -#include "vm-state-inl.h" +#include "src/v8.h" + +#include "src/accessors.h" +#include "src/allocation-site-scopes.h" +#include "src/api.h" +#include "src/arguments.h" +#include "src/bootstrapper.h" +#include "src/codegen.h" +#include "src/compilation-cache.h" +#include "src/compiler.h" +#include "src/conversions.h" +#include "src/cpu.h" +#include "src/cpu-profiler.h" +#include "src/dateparser-inl.h" +#include "src/debug.h" +#include "src/deoptimizer.h" +#include "src/date.h" +#include "src/execution.h" +#include "src/full-codegen.h" +#include "src/global-handles.h" +#include "src/isolate-inl.h" +#include "src/jsregexp.h" +#include "src/jsregexp-inl.h" +#include "src/json-parser.h" +#include "src/json-stringifier.h" +#include "src/liveedit.h" +#include "src/misc-intrinsics.h" +#include "src/parser.h" +#include "src/platform.h" +#include "src/runtime-profiler.h" +#include "src/runtime.h" +#include "src/scopeinfo.h" +#include "src/smart-pointers.h" +#include "src/string-search.h" +#include "src/stub-cache.h" +#include "src/uri.h" +#include "src/v8threads.h" +#include "src/vm-state-inl.h" #ifdef V8_I18N_SUPPORT -#include "i18n.h" +#include "src/i18n.h" #include "unicode/brkiter.h" #include "unicode/calendar.h" #include "unicode/coll.h" @@ -105,6 +82,12 @@ namespace internal { #define RUNTIME_ASSERT(value) \ if (!(value)) return isolate->ThrowIllegalOperation(); +#define RUNTIME_ASSERT_HANDLIFIED(value, T) \ + if (!(value)) { \ + isolate->ThrowIllegalOperation(); \ + return MaybeHandle<T>(); \ + } + // Cast the given object to a value of the specified type and store // it in a variable with the given name. If the object is not of the // expected type call IllegalOperation and return. @@ -116,6 +99,10 @@ namespace internal { RUNTIME_ASSERT(args[index]->Is##Type()); \ Handle<Type> name = args.at<Type>(index); +#define CONVERT_NUMBER_ARG_HANDLE_CHECKED(name, index) \ + RUNTIME_ASSERT(args[index]->IsNumber()); \ + Handle<Object> name = args.at<Object>(index); + // Cast the given object to a boolean and store it in a variable with // the given name. If the object is not a boolean call IllegalOperation // and return. @@ -153,25 +140,13 @@ namespace internal { PropertyDetails name = PropertyDetails(Smi::cast(args[index])); -// Assert that the given argument has a valid value for a StrictModeFlag -// and store it in a StrictModeFlag variable with the given name. +// Assert that the given argument has a valid value for a StrictMode +// and store it in a StrictMode variable with the given name. #define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \ RUNTIME_ASSERT(args[index]->IsSmi()); \ - RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \ - args.smi_at(index) == kNonStrictMode); \ - StrictModeFlag name = \ - static_cast<StrictModeFlag>(args.smi_at(index)); - - -// Assert that the given argument has a valid value for a LanguageMode -// and store it in a LanguageMode variable with the given name. -#define CONVERT_LANGUAGE_MODE_ARG(name, index) \ - ASSERT(args[index]->IsSmi()); \ - ASSERT(args.smi_at(index) == CLASSIC_MODE || \ - args.smi_at(index) == STRICT_MODE || \ - args.smi_at(index) == EXTENDED_MODE); \ - LanguageMode name = \ - static_cast<LanguageMode>(args.smi_at(index)); + RUNTIME_ASSERT(args.smi_at(index) == STRICT || \ + args.smi_at(index) == SLOPPY); \ + StrictMode name = static_cast<StrictMode>(args.smi_at(index)); static Handle<Map> ComputeObjectLiteralMap( @@ -221,19 +196,17 @@ static Handle<Map> ComputeObjectLiteralMap( return isolate->factory()->ObjectLiteralMapFromCache(context, keys); } *is_result_from_cache = false; - return isolate->factory()->CopyMap( - Handle<Map>(context->object_function()->initial_map()), - number_of_properties); + return Map::Create(handle(context->object_function()), number_of_properties); } -static Handle<Object> CreateLiteralBoilerplate( +MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate( Isolate* isolate, Handle<FixedArray> literals, Handle<FixedArray> constant_properties); -static Handle<Object> CreateObjectLiteralBoilerplate( +MUST_USE_RESULT static MaybeHandle<Object> CreateObjectLiteralBoilerplate( Isolate* isolate, Handle<FixedArray> literals, Handle<FixedArray> constant_properties, @@ -259,9 +232,11 @@ static Handle<Object> CreateObjectLiteralBoilerplate( constant_properties, &is_result_from_cache); + PretenureFlag pretenure_flag = + isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED; + Handle<JSObject> boilerplate = - isolate->factory()->NewJSObjectFromMap( - map, isolate->heap()->GetPretenureMode()); + isolate->factory()->NewJSObjectFromMap(map, pretenure_flag); // Normalize the elements of the boilerplate to save space if needed. if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate); @@ -270,13 +245,14 @@ static Handle<Object> CreateObjectLiteralBoilerplate( int length = constant_properties->length(); bool should_transform = !is_result_from_cache && boilerplate->HasFastProperties(); - if (should_transform || has_function_literal) { - // Normalize the properties of object to avoid n^2 behavior - // when extending the object multiple properties. Indicate the number of - // properties to be added. + bool should_normalize = should_transform || has_function_literal; + if (should_normalize) { + // TODO(verwaest): We might not want to ever normalize here. JSObject::NormalizeProperties( boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2); } + Object::ValueType value_type = should_normalize + ? Object::FORCE_TAGGED : Object::OPTIMAL_REPRESENTATION; // TODO(verwaest): Support tracking representations in the boilerplate. for (int index = 0; index < length; index +=2) { @@ -286,28 +262,30 @@ static Handle<Object> CreateObjectLiteralBoilerplate( // The value contains the constant_properties of a // simple object or array literal. Handle<FixedArray> array = Handle<FixedArray>::cast(value); - value = CreateLiteralBoilerplate(isolate, literals, array); - if (value.is_null()) return value; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, value, + CreateLiteralBoilerplate(isolate, literals, array), + Object); } - Handle<Object> result; + MaybeHandle<Object> maybe_result; uint32_t element_index = 0; StoreMode mode = value->IsJSObject() ? FORCE_FIELD : ALLOW_AS_CONSTANT; if (key->IsInternalizedString()) { if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) { // Array index as string (uint32). - result = JSObject::SetOwnElement( - boilerplate, element_index, value, kNonStrictMode); + maybe_result = JSObject::SetOwnElement( + boilerplate, element_index, value, SLOPPY); } else { Handle<String> name(String::cast(*key)); ASSERT(!name->AsArrayIndex(&element_index)); - result = JSObject::SetLocalPropertyIgnoreAttributes( + maybe_result = JSObject::SetOwnPropertyIgnoreAttributes( boilerplate, name, value, NONE, - Object::OPTIMAL_REPRESENTATION, mode); + value_type, mode); } } else if (key->ToArrayIndex(&element_index)) { // Array index (uint32). - result = JSObject::SetOwnElement( - boilerplate, element_index, value, kNonStrictMode); + maybe_result = JSObject::SetOwnElement( + boilerplate, element_index, value, SLOPPY); } else { // Non-uint32 number. ASSERT(key->IsNumber()); @@ -315,17 +293,16 @@ static Handle<Object> CreateObjectLiteralBoilerplate( char arr[100]; Vector<char> buffer(arr, ARRAY_SIZE(arr)); const char* str = DoubleToCString(num, buffer); - Handle<String> name = - isolate->factory()->NewStringFromAscii(CStrVector(str)); - result = JSObject::SetLocalPropertyIgnoreAttributes( + Handle<String> name = isolate->factory()->NewStringFromAsciiChecked(str); + maybe_result = JSObject::SetOwnPropertyIgnoreAttributes( boilerplate, name, value, NONE, - Object::OPTIMAL_REPRESENTATION, mode); + value_type, mode); } // If setting the property on the boilerplate throws an // exception, the exception is converted to an empty handle in // the handle based operations. In that case, we need to // convert back to an exception. - if (result.is_null()) return result; + RETURN_ON_EXCEPTION(isolate, maybe_result, Object); } // Transform to fast properties if necessary. For object literals with @@ -341,25 +318,30 @@ static Handle<Object> CreateObjectLiteralBoilerplate( } -MaybeObject* TransitionElements(Handle<Object> object, - ElementsKind to_kind, - Isolate* isolate) { +MUST_USE_RESULT static MaybeHandle<Object> TransitionElements( + Handle<Object> object, + ElementsKind to_kind, + Isolate* isolate) { HandleScope scope(isolate); - if (!object->IsJSObject()) return isolate->ThrowIllegalOperation(); + if (!object->IsJSObject()) { + isolate->ThrowIllegalOperation(); + return MaybeHandle<Object>(); + } ElementsKind from_kind = Handle<JSObject>::cast(object)->map()->elements_kind(); if (Map::IsValidElementsTransition(from_kind, to_kind)) { JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind); - return *object; + return object; } - return isolate->ThrowIllegalOperation(); + isolate->ThrowIllegalOperation(); + return MaybeHandle<Object>(); } static const int kSmiLiteralMinimumLength = 1024; -Handle<Object> Runtime::CreateArrayLiteralBoilerplate( +MaybeHandle<Object> Runtime::CreateArrayLiteralBoilerplate( Isolate* isolate, Handle<FixedArray> literals, Handle<FixedArray> elements) { @@ -367,23 +349,25 @@ Handle<Object> Runtime::CreateArrayLiteralBoilerplate( Handle<JSFunction> constructor( JSFunction::NativeContextFromLiterals(*literals)->array_function()); + PretenureFlag pretenure_flag = + isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED; + Handle<JSArray> object = Handle<JSArray>::cast( - isolate->factory()->NewJSObject( - constructor, isolate->heap()->GetPretenureMode())); + isolate->factory()->NewJSObject(constructor, pretenure_flag)); ElementsKind constant_elements_kind = static_cast<ElementsKind>(Smi::cast(elements->get(0))->value()); Handle<FixedArrayBase> constant_elements_values( FixedArrayBase::cast(elements->get(1))); - ASSERT(IsFastElementsKind(constant_elements_kind)); - Context* native_context = isolate->context()->native_context(); - Object* maybe_maps_array = native_context->js_array_maps(); - ASSERT(!maybe_maps_array->IsUndefined()); - Object* maybe_map = FixedArray::cast(maybe_maps_array)->get( - constant_elements_kind); - ASSERT(maybe_map->IsMap()); - object->set_map(Map::cast(maybe_map)); + { DisallowHeapAllocation no_gc; + ASSERT(IsFastElementsKind(constant_elements_kind)); + Context* native_context = isolate->context()->native_context(); + Object* maps_array = native_context->js_array_maps(); + ASSERT(!maps_array->IsUndefined()); + Object* map = FixedArray::cast(maps_array)->get(constant_elements_kind); + object->set_map(Map::cast(map)); + } Handle<FixedArrayBase> copied_elements_values; if (IsFastDoubleElementsKind(constant_elements_kind)) { @@ -411,14 +395,15 @@ Handle<Object> Runtime::CreateArrayLiteralBoilerplate( isolate->factory()->CopyFixedArray(fixed_array_values); copied_elements_values = fixed_array_values_copy; for (int i = 0; i < fixed_array_values->length(); i++) { - Object* current = fixed_array_values->get(i); - if (current->IsFixedArray()) { + if (fixed_array_values->get(i)->IsFixedArray()) { // The value contains the constant_properties of a // simple object or array literal. Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i))); - Handle<Object> result = - CreateLiteralBoilerplate(isolate, literals, fa); - if (result.is_null()) return result; + Handle<Object> result; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, result, + CreateLiteralBoilerplate(isolate, literals, fa), + Object); fixed_array_values_copy->set(i, *result); } } @@ -434,20 +419,19 @@ Handle<Object> Runtime::CreateArrayLiteralBoilerplate( ElementsKind elements_kind = object->GetElementsKind(); if (!IsFastObjectElementsKind(elements_kind)) { if (IsFastHoleyElementsKind(elements_kind)) { - CHECK(!TransitionElements(object, FAST_HOLEY_ELEMENTS, - isolate)->IsFailure()); + TransitionElements(object, FAST_HOLEY_ELEMENTS, isolate).Check(); } else { - CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure()); + TransitionElements(object, FAST_ELEMENTS, isolate).Check(); } } } - object->ValidateElements(); + JSObject::ValidateElements(object); return object; } -static Handle<Object> CreateLiteralBoilerplate( +MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate( Isolate* isolate, Handle<FixedArray> literals, Handle<FixedArray> array) { @@ -471,12 +455,12 @@ static Handle<Object> CreateLiteralBoilerplate( isolate, literals, elements); default: UNREACHABLE(); - return Handle<Object>::null(); + return MaybeHandle<Object>(); } } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) { +RUNTIME_FUNCTION(RuntimeHidden_CreateObjectLiteral) { HandleScope scope(isolate); ASSERT(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); @@ -486,24 +470,29 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) { bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0; + RUNTIME_ASSERT(literals_index >= 0 && literals_index < literals->length()); + // Check if boilerplate exists. If not, create it first. Handle<Object> literal_site(literals->get(literals_index), isolate); Handle<AllocationSite> site; Handle<JSObject> boilerplate; if (*literal_site == isolate->heap()->undefined_value()) { - Handle<Object> raw_boilerplate = CreateObjectLiteralBoilerplate( - isolate, - literals, - constant_properties, - should_have_fast_elements, - has_function_literal); - RETURN_IF_EMPTY_HANDLE(isolate, raw_boilerplate); + Handle<Object> raw_boilerplate; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, raw_boilerplate, + CreateObjectLiteralBoilerplate( + isolate, + literals, + constant_properties, + should_have_fast_elements, + has_function_literal)); boilerplate = Handle<JSObject>::cast(raw_boilerplate); AllocationSiteCreationContext creation_context(isolate); site = creation_context.EnterNewScope(); - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::DeepWalk(boilerplate, &creation_context)); + RETURN_FAILURE_ON_EXCEPTION( + isolate, + JSObject::DeepWalk(boilerplate, &creation_context)); creation_context.ExitScope(site, boilerplate); // Update the functions literal and return the boilerplate. @@ -516,14 +505,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) { AllocationSiteUsageContext usage_context(isolate, site, true); usage_context.EnterNewScope(); - Handle<Object> copy = JSObject::DeepCopy(boilerplate, &usage_context); + MaybeHandle<Object> maybe_copy = JSObject::DeepCopy( + boilerplate, &usage_context); usage_context.ExitScope(site, boilerplate); - RETURN_IF_EMPTY_HANDLE(isolate, copy); + Handle<Object> copy; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, copy, maybe_copy); return *copy; } -static Handle<AllocationSite> GetLiteralAllocationSite( +MUST_USE_RESULT static MaybeHandle<AllocationSite> GetLiteralAllocationSite( Isolate* isolate, Handle<FixedArray> literals, int literals_index, @@ -533,9 +524,11 @@ static Handle<AllocationSite> GetLiteralAllocationSite( Handle<AllocationSite> site; if (*literal_site == isolate->heap()->undefined_value()) { ASSERT(*elements != isolate->heap()->empty_fixed_array()); - Handle<Object> boilerplate = - Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements); - if (boilerplate.is_null()) return Handle<AllocationSite>::null(); + Handle<Object> boilerplate; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, boilerplate, + Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements), + AllocationSite); AllocationSiteCreationContext creation_context(isolate); site = creation_context.EnterNewScope(); @@ -554,14 +547,18 @@ static Handle<AllocationSite> GetLiteralAllocationSite( } -static MaybeObject* CreateArrayLiteralImpl(Isolate* isolate, +static MaybeHandle<JSObject> CreateArrayLiteralImpl(Isolate* isolate, Handle<FixedArray> literals, int literals_index, Handle<FixedArray> elements, int flags) { - Handle<AllocationSite> site = GetLiteralAllocationSite(isolate, literals, - literals_index, elements); - RETURN_IF_EMPTY_HANDLE(isolate, site); + RUNTIME_ASSERT_HANDLIFIED(literals_index >= 0 && + literals_index < literals->length(), JSObject); + Handle<AllocationSite> site; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, site, + GetLiteralAllocationSite(isolate, literals, literals_index, elements), + JSObject); bool enable_mementos = (flags & ArrayLiteral::kDisableMementos) == 0; Handle<JSObject> boilerplate(JSObject::cast(site->transition_info())); @@ -570,15 +567,14 @@ static MaybeObject* CreateArrayLiteralImpl(Isolate* isolate, JSObject::DeepCopyHints hints = (flags & ArrayLiteral::kShallowElements) == 0 ? JSObject::kNoHints : JSObject::kObjectIsShallowArray; - Handle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context, - hints); + MaybeHandle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context, + hints); usage_context.ExitScope(site, boilerplate); - RETURN_IF_EMPTY_HANDLE(isolate, copy); - return *copy; + return copy; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) { +RUNTIME_FUNCTION(RuntimeHidden_CreateArrayLiteral) { HandleScope scope(isolate); ASSERT(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); @@ -586,50 +582,83 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) { CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2); CONVERT_SMI_ARG_CHECKED(flags, 3); - return CreateArrayLiteralImpl(isolate, literals, literals_index, elements, - flags); + Handle<JSObject> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, + CreateArrayLiteralImpl(isolate, literals, literals_index, elements, + flags)); + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralStubBailout) { +RUNTIME_FUNCTION(RuntimeHidden_CreateArrayLiteralStubBailout) { HandleScope scope(isolate); ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); CONVERT_SMI_ARG_CHECKED(literals_index, 1); CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2); - return CreateArrayLiteralImpl(isolate, literals, literals_index, elements, - ArrayLiteral::kShallowElements); + Handle<JSObject> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, + CreateArrayLiteralImpl(isolate, literals, literals_index, elements, + ArrayLiteral::kShallowElements)); + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateSymbol) { +RUNTIME_FUNCTION(Runtime_CreateSymbol) { HandleScope scope(isolate); ASSERT(args.length() == 1); - Handle<Object> name(args[0], isolate); + CONVERT_ARG_HANDLE_CHECKED(Object, name, 0); RUNTIME_ASSERT(name->IsString() || name->IsUndefined()); - Symbol* symbol; - MaybeObject* maybe = isolate->heap()->AllocateSymbol(); - if (!maybe->To(&symbol)) return maybe; + Handle<Symbol> symbol = isolate->factory()->NewSymbol(); if (name->IsString()) symbol->set_name(*name); - return symbol; + return *symbol; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreatePrivateSymbol) { +RUNTIME_FUNCTION(Runtime_CreatePrivateSymbol) { HandleScope scope(isolate); ASSERT(args.length() == 1); - Handle<Object> name(args[0], isolate); + CONVERT_ARG_HANDLE_CHECKED(Object, name, 0); RUNTIME_ASSERT(name->IsString() || name->IsUndefined()); - Symbol* symbol; - MaybeObject* maybe = isolate->heap()->AllocatePrivateSymbol(); - if (!maybe->To(&symbol)) return maybe; + Handle<Symbol> symbol = isolate->factory()->NewPrivateSymbol(); if (name->IsString()) symbol->set_name(*name); - return symbol; + return *symbol; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolName) { +RUNTIME_FUNCTION(Runtime_CreateGlobalPrivateSymbol) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(String, name, 0); + Handle<JSObject> registry = isolate->GetSymbolRegistry(); + Handle<String> part = isolate->factory()->private_intern_string(); + Handle<Object> privates; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, privates, Object::GetPropertyOrElement(registry, part)); + Handle<Object> symbol; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, symbol, Object::GetPropertyOrElement(privates, name)); + if (!symbol->IsSymbol()) { + ASSERT(symbol->IsUndefined()); + symbol = isolate->factory()->NewPrivateSymbol(); + Handle<Symbol>::cast(symbol)->set_name(*name); + JSObject::SetProperty(Handle<JSObject>::cast(privates), + name, symbol, NONE, STRICT).Assert(); + } + return *symbol; +} + + +RUNTIME_FUNCTION(Runtime_NewSymbolWrapper) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(Symbol, symbol, 0); + return *Object::ToObject(isolate, symbol).ToHandleChecked(); +} + + +RUNTIME_FUNCTION(Runtime_SymbolDescription) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(Symbol, symbol, 0); @@ -637,7 +666,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolName) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolIsPrivate) { +RUNTIME_FUNCTION(Runtime_SymbolRegistry) { + HandleScope scope(isolate); + ASSERT(args.length() == 0); + return *isolate->GetSymbolRegistry(); +} + + +RUNTIME_FUNCTION(Runtime_SymbolIsPrivate) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(Symbol, symbol, 0); @@ -645,49 +681,47 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolIsPrivate) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_CreateJSProxy) { + HandleScope scope(isolate); ASSERT(args.length() == 2); - CONVERT_ARG_CHECKED(JSReceiver, handler, 0); - Object* prototype = args[1]; - Object* used_prototype = - prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value(); - return isolate->heap()->AllocateJSProxy(handler, used_prototype); + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0); + CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); + if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value(); + return *isolate->factory()->NewJSProxy(handler, prototype); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_CreateJSFunctionProxy) { + HandleScope scope(isolate); ASSERT(args.length() == 4); - CONVERT_ARG_CHECKED(JSReceiver, handler, 0); - Object* call_trap = args[1]; + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0); + CONVERT_ARG_HANDLE_CHECKED(Object, call_trap, 1); RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy()); - CONVERT_ARG_CHECKED(JSFunction, construct_trap, 2); - Object* prototype = args[3]; - Object* used_prototype = - prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value(); - return isolate->heap()->AllocateJSFunctionProxy( - handler, call_trap, construct_trap, used_prototype); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, construct_trap, 2); + CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 3); + if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value(); + return *isolate->factory()->NewJSFunctionProxy( + handler, call_trap, construct_trap, prototype); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) { +RUNTIME_FUNCTION(Runtime_IsJSProxy) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); - Object* obj = args[0]; + CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); return isolate->heap()->ToBoolean(obj->IsJSProxy()); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) { +RUNTIME_FUNCTION(Runtime_IsJSFunctionProxy) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); - Object* obj = args[0]; + CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy()); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) { +RUNTIME_FUNCTION(Runtime_GetHandler) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSProxy, proxy, 0); @@ -695,7 +729,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) { +RUNTIME_FUNCTION(Runtime_GetCallTrap) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0); @@ -703,7 +737,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) { +RUNTIME_FUNCTION(Runtime_GetConstructTrap) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0); @@ -711,7 +745,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) { +RUNTIME_FUNCTION(Runtime_Fix) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0); @@ -731,8 +765,9 @@ void Runtime::FreeArrayBuffer(Isolate* isolate, size_t allocated_length = NumberToSize( isolate, phantom_array_buffer->byte_length()); - isolate->heap()->AdjustAmountOfExternalAllocatedMemory( - -static_cast<int64_t>(allocated_length)); + reinterpret_cast<v8::Isolate*>(isolate) + ->AdjustAmountOfExternalAllocatedMemory( + -static_cast<int64_t>(allocated_length)); CHECK(V8::ArrayBufferAllocator() != NULL); V8::ArrayBufferAllocator()->Free( phantom_array_buffer->backing_store(), @@ -777,7 +812,7 @@ bool Runtime::SetupArrayBufferAllocatingData( data = V8::ArrayBufferAllocator()->Allocate(allocated_length); } else { data = - V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length); + V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length); } if (data == NULL) return false; } else { @@ -786,47 +821,57 @@ bool Runtime::SetupArrayBufferAllocatingData( SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length); - isolate->heap()->AdjustAmountOfExternalAllocatedMemory(allocated_length); + reinterpret_cast<v8::Isolate*>(isolate) + ->AdjustAmountOfExternalAllocatedMemory(allocated_length); return true; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferInitialize) { +void Runtime::NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer) { + Isolate* isolate = array_buffer->GetIsolate(); + for (Handle<Object> view_obj(array_buffer->weak_first_view(), isolate); + !view_obj->IsUndefined();) { + Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj)); + if (view->IsJSTypedArray()) { + JSTypedArray::cast(*view)->Neuter(); + } else if (view->IsJSDataView()) { + JSDataView::cast(*view)->Neuter(); + } else { + UNREACHABLE(); + } + view_obj = handle(view->weak_next(), isolate); + } + array_buffer->Neuter(); +} + + +RUNTIME_FUNCTION(Runtime_ArrayBufferInitialize) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); - CONVERT_ARG_HANDLE_CHECKED(Object, byteLength, 1); - size_t allocated_length; - if (byteLength->IsSmi()) { - allocated_length = Smi::cast(*byteLength)->value(); - } else { - ASSERT(byteLength->IsHeapNumber()); - double value = HeapNumber::cast(*byteLength)->value(); - - ASSERT(value >= 0); - - if (value > std::numeric_limits<size_t>::max()) { - return isolate->Throw( - *isolate->factory()->NewRangeError("invalid_array_buffer_length", - HandleVector<Object>(NULL, 0))); - } - - allocated_length = static_cast<size_t>(value); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(byteLength, 1); + if (!holder->byte_length()->IsUndefined()) { + // ArrayBuffer is already initialized; probably a fuzz test. + return *holder; + } + size_t allocated_length = 0; + if (!TryNumberToSize(isolate, *byteLength, &allocated_length)) { + return isolate->Throw( + *isolate->factory()->NewRangeError("invalid_array_buffer_length", + HandleVector<Object>(NULL, 0))); } - if (!Runtime::SetupArrayBufferAllocatingData(isolate, holder, allocated_length)) { - return isolate->Throw(*isolate->factory()-> - NewRangeError("invalid_array_buffer_length", - HandleVector<Object>(NULL, 0))); + return isolate->Throw( + *isolate->factory()->NewRangeError("invalid_array_buffer_length", + HandleVector<Object>(NULL, 0))); } - return *holder; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferGetByteLength) { +RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0); @@ -834,18 +879,22 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferGetByteLength) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) { +RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) { HandleScope scope(isolate); ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0); CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1); - CONVERT_DOUBLE_ARG_CHECKED(first, 2); - size_t start = static_cast<size_t>(first); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(first, 2); + RUNTIME_ASSERT(!source.is_identical_to(target)); + size_t start = 0; + RUNTIME_ASSERT(TryNumberToSize(isolate, *first, &start)); size_t target_length = NumberToSize(isolate, target->byte_length()); if (target_length == 0) return isolate->heap()->undefined_value(); - ASSERT(NumberToSize(isolate, source->byte_length()) - target_length >= start); + size_t source_byte_length = NumberToSize(isolate, source->byte_length()); + RUNTIME_ASSERT(start <= source_byte_length); + RUNTIME_ASSERT(source_byte_length - start >= target_length); uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store()); uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store()); CopyBytes(target_data, source_data + start, target_length); @@ -853,105 +902,138 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferIsView) { +RUNTIME_FUNCTION(Runtime_ArrayBufferIsView) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(Object, object, 0); - return object->IsJSArrayBufferView() - ? isolate->heap()->true_value() - : isolate->heap()->false_value(); + return isolate->heap()->ToBoolean(object->IsJSArrayBufferView()); +} + + +RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0); + if (array_buffer->backing_store() == NULL) { + CHECK(Smi::FromInt(0) == array_buffer->byte_length()); + return isolate->heap()->undefined_value(); + } + ASSERT(!array_buffer->is_external()); + void* backing_store = array_buffer->backing_store(); + size_t byte_length = NumberToSize(isolate, array_buffer->byte_length()); + array_buffer->set_is_external(true); + Runtime::NeuterArrayBuffer(array_buffer); + V8::ArrayBufferAllocator()->Free(backing_store, byte_length); + return isolate->heap()->undefined_value(); } void Runtime::ArrayIdToTypeAndSize( - int arrayId, ExternalArrayType* array_type, size_t* element_size) { + int arrayId, + ExternalArrayType* array_type, + ElementsKind* external_elements_kind, + ElementsKind* fixed_elements_kind, + size_t* element_size) { switch (arrayId) { - case ARRAY_ID_UINT8: - *array_type = kExternalUnsignedByteArray; - *element_size = 1; - break; - case ARRAY_ID_INT8: - *array_type = kExternalByteArray; - *element_size = 1; - break; - case ARRAY_ID_UINT16: - *array_type = kExternalUnsignedShortArray; - *element_size = 2; - break; - case ARRAY_ID_INT16: - *array_type = kExternalShortArray; - *element_size = 2; - break; - case ARRAY_ID_UINT32: - *array_type = kExternalUnsignedIntArray; - *element_size = 4; - break; - case ARRAY_ID_INT32: - *array_type = kExternalIntArray; - *element_size = 4; - break; - case ARRAY_ID_FLOAT32: - *array_type = kExternalFloatArray; - *element_size = 4; - break; - case ARRAY_ID_FLOAT64: - *array_type = kExternalDoubleArray; - *element_size = 8; - break; - case ARRAY_ID_UINT8C: - *array_type = kExternalPixelArray; - *element_size = 1; +#define ARRAY_ID_CASE(Type, type, TYPE, ctype, size) \ + case ARRAY_ID_##TYPE: \ + *array_type = kExternal##Type##Array; \ + *external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS; \ + *fixed_elements_kind = TYPE##_ELEMENTS; \ + *element_size = size; \ break; + + TYPED_ARRAYS(ARRAY_ID_CASE) +#undef ARRAY_ID_CASE + default: UNREACHABLE(); } } -RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) { +RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) { HandleScope scope(isolate); ASSERT(args.length() == 5); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); CONVERT_SMI_ARG_CHECKED(arrayId, 1); - CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 2); - CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3); - CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4); + CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset_object, 3); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length_object, 4); - ASSERT(holder->GetInternalFieldCount() == - v8::ArrayBufferView::kInternalFieldCount); - for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { - holder->SetInternalField(i, Smi::FromInt(0)); - } + RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST && + arrayId <= Runtime::ARRAY_ID_LAST); - ExternalArrayType array_type = kExternalByteArray; // Bogus initialization. + ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization. size_t element_size = 1; // Bogus initialization. - Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &element_size); + ElementsKind external_elements_kind = + EXTERNAL_INT8_ELEMENTS; // Bogus initialization. + ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization. + Runtime::ArrayIdToTypeAndSize(arrayId, + &array_type, + &external_elements_kind, + &fixed_elements_kind, + &element_size); + RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind); - holder->set_buffer(*buffer); - holder->set_byte_offset(*byte_offset_object); - holder->set_byte_length(*byte_length_object); + size_t byte_offset = 0; + size_t byte_length = 0; + RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset_object, &byte_offset)); + RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length_object, &byte_length)); + + if (maybe_buffer->IsJSArrayBuffer()) { + Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer); + size_t array_buffer_byte_length = + NumberToSize(isolate, buffer->byte_length()); + RUNTIME_ASSERT(byte_offset <= array_buffer_byte_length); + RUNTIME_ASSERT(array_buffer_byte_length - byte_offset >= byte_length); + } else { + RUNTIME_ASSERT(maybe_buffer->IsNull()); + } - size_t byte_offset = NumberToSize(isolate, *byte_offset_object); - size_t byte_length = NumberToSize(isolate, *byte_length_object); - ASSERT(byte_length % element_size == 0); + RUNTIME_ASSERT(byte_length % element_size == 0); size_t length = byte_length / element_size; if (length > static_cast<unsigned>(Smi::kMaxValue)) { - return isolate->Throw(*isolate->factory()-> - NewRangeError("invalid_typed_array_length", - HandleVector<Object>(NULL, 0))); + return isolate->Throw( + *isolate->factory()->NewRangeError("invalid_typed_array_length", + HandleVector<Object>(NULL, 0))); } + // All checks are done, now we can modify objects. + + ASSERT(holder->GetInternalFieldCount() == + v8::ArrayBufferView::kInternalFieldCount); + for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { + holder->SetInternalField(i, Smi::FromInt(0)); + } Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length); holder->set_length(*length_obj); - holder->set_weak_next(buffer->weak_first_view()); - buffer->set_weak_first_view(*holder); + holder->set_byte_offset(*byte_offset_object); + holder->set_byte_length(*byte_length_object); - Handle<ExternalArray> elements = - isolate->factory()->NewExternalArray( - static_cast<int>(length), array_type, - static_cast<uint8_t*>(buffer->backing_store()) + byte_offset); - holder->set_elements(*elements); + if (!maybe_buffer->IsNull()) { + Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer); + holder->set_buffer(*buffer); + holder->set_weak_next(buffer->weak_first_view()); + buffer->set_weak_first_view(*holder); + + Handle<ExternalArray> elements = + isolate->factory()->NewExternalArray( + static_cast<int>(length), array_type, + static_cast<uint8_t*>(buffer->backing_store()) + byte_offset); + Handle<Map> map = + JSObject::GetElementsTransitionMap(holder, external_elements_kind); + JSObject::SetMapAndElements(holder, map, elements); + ASSERT(IsExternalArrayElementsKind(holder->map()->elements_kind())); + } else { + holder->set_buffer(Smi::FromInt(0)); + holder->set_weak_next(isolate->heap()->undefined_value()); + Handle<FixedTypedArrayBase> elements = + isolate->factory()->NewFixedTypedArray( + static_cast<int>(length), array_type); + holder->set_elements(*elements); + } return isolate->heap()->undefined_value(); } @@ -961,30 +1043,37 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) { // initializes backing store using memove. // // Returns true if backing store was initialized or false otherwise. -RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) { +RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) { HandleScope scope(isolate); ASSERT(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); CONVERT_SMI_ARG_CHECKED(arrayId, 1); CONVERT_ARG_HANDLE_CHECKED(Object, source, 2); - CONVERT_ARG_HANDLE_CHECKED(Object, length_obj, 3); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3); - ASSERT(holder->GetInternalFieldCount() == - v8::ArrayBufferView::kInternalFieldCount); - for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { - holder->SetInternalField(i, Smi::FromInt(0)); - } + RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST && + arrayId <= Runtime::ARRAY_ID_LAST); - ExternalArrayType array_type = kExternalByteArray; // Bogus initialization. + ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization. size_t element_size = 1; // Bogus initialization. - Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &element_size); + ElementsKind external_elements_kind = + EXTERNAL_INT8_ELEMENTS; // Bogus intialization. + ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization. + Runtime::ArrayIdToTypeAndSize(arrayId, + &array_type, + &external_elements_kind, + &fixed_elements_kind, + &element_size); + + RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind); Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); if (source->IsJSTypedArray() && JSTypedArray::cast(*source)->type() == array_type) { length_obj = Handle<Object>(JSTypedArray::cast(*source)->length(), isolate); } - size_t length = NumberToSize(isolate, *length_obj); + size_t length = 0; + RUNTIME_ASSERT(TryNumberToSize(isolate, *length_obj, &length)); if ((length > static_cast<unsigned>(Smi::kMaxValue)) || (length > (kMaxInt / element_size))) { @@ -994,6 +1083,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) { } size_t byte_length = length * element_size; + ASSERT(holder->GetInternalFieldCount() == + v8::ArrayBufferView::kInternalFieldCount); + for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { + holder->SetInternalField(i, Smi::FromInt(0)); + } + // NOTE: not initializing backing store. // We assume that the caller of this function will initialize holder // with the loop @@ -1030,7 +1125,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) { isolate->factory()->NewExternalArray( static_cast<int>(length), array_type, static_cast<uint8_t*>(buffer->backing_store())); - holder->set_elements(*elements); + Handle<Map> map = JSObject::GetElementsTransitionMap( + holder, external_elements_kind); + JSObject::SetMapAndElements(holder, map, elements); if (source->IsJSTypedArray()) { Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source)); @@ -1038,41 +1135,43 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) { if (typed_array->type() == holder->type()) { uint8_t* backing_store = static_cast<uint8_t*>( - JSArrayBuffer::cast(typed_array->buffer())->backing_store()); + typed_array->GetBuffer()->backing_store()); size_t source_byte_offset = NumberToSize(isolate, typed_array->byte_offset()); memcpy( buffer->backing_store(), backing_store + source_byte_offset, byte_length); - return *isolate->factory()->true_value(); - } else { - return *isolate->factory()->false_value(); + return isolate->heap()->true_value(); } } - return *isolate->factory()->false_value(); + return isolate->heap()->false_value(); } -#define TYPED_ARRAY_GETTER(getter, accessor) \ - RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGet##getter) { \ +#define BUFFER_VIEW_GETTER(Type, getter, accessor) \ + RUNTIME_FUNCTION(Runtime_##Type##Get##getter) { \ HandleScope scope(isolate); \ ASSERT(args.length() == 1); \ - CONVERT_ARG_HANDLE_CHECKED(Object, holder, 0); \ - if (!holder->IsJSTypedArray()) \ - return isolate->Throw(*isolate->factory()->NewTypeError( \ - "not_typed_array", HandleVector<Object>(NULL, 0))); \ - Handle<JSTypedArray> typed_array(JSTypedArray::cast(*holder)); \ - return typed_array->accessor(); \ + CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0); \ + return holder->accessor(); \ } -TYPED_ARRAY_GETTER(Buffer, buffer) -TYPED_ARRAY_GETTER(ByteLength, byte_length) -TYPED_ARRAY_GETTER(ByteOffset, byte_offset) -TYPED_ARRAY_GETTER(Length, length) +BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length) +BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset) +BUFFER_VIEW_GETTER(TypedArray, Length, length) +BUFFER_VIEW_GETTER(DataView, Buffer, buffer) + +#undef BUFFER_VIEW_GETTER + +RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); + return *holder->GetBuffer(); +} -#undef TYPED_ARRAY_GETTER // Return codes for Runtime_TypedArraySetFastCases. // Should be synchronized with typedarray.js natives. @@ -1089,22 +1188,24 @@ enum TypedArraySetResultCodes { }; -RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) { +RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) { HandleScope scope(isolate); - CONVERT_ARG_HANDLE_CHECKED(Object, target_obj, 0); - CONVERT_ARG_HANDLE_CHECKED(Object, source_obj, 1); - CONVERT_ARG_HANDLE_CHECKED(Object, offset_obj, 2); - - if (!target_obj->IsJSTypedArray()) + ASSERT(args.length() == 3); + if (!args[0]->IsJSTypedArray()) return isolate->Throw(*isolate->factory()->NewTypeError( "not_typed_array", HandleVector<Object>(NULL, 0))); - if (!source_obj->IsJSTypedArray()) + if (!args[1]->IsJSTypedArray()) return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY); + CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0); + CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2); + Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj)); Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj)); - size_t offset = NumberToSize(isolate, *offset_obj); + size_t offset = 0; + RUNTIME_ASSERT(TryNumberToSize(isolate, *offset_obj, &offset)); size_t target_length = NumberToSize(isolate, target->length()); size_t source_length = NumberToSize(isolate, source->length()); size_t target_byte_length = NumberToSize(isolate, target->byte_length()); @@ -1119,10 +1220,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) { size_t source_offset = NumberToSize(isolate, source->byte_offset()); uint8_t* target_base = static_cast<uint8_t*>( - JSArrayBuffer::cast(target->buffer())->backing_store()) + target_offset; + target->GetBuffer()->backing_store()) + target_offset; uint8_t* source_base = static_cast<uint8_t*>( - JSArrayBuffer::cast(source->buffer())->backing_store()) + source_offset; + source->GetBuffer()->backing_store()) + source_offset; // Typed arrays of the same type: use memmove. if (target->type() == source->type()) { @@ -1138,8 +1239,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) { target_base + target_byte_length > source_base)) { // We do not support overlapping ArrayBuffers ASSERT( - JSArrayBuffer::cast(target->buffer())->backing_store() == - JSArrayBuffer::cast(source->buffer())->backing_store()); + target->GetBuffer()->backing_store() == + source->GetBuffer()->backing_store()); return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING); } else { // Non-overlapping typed arrays return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING); @@ -1147,28 +1248,44 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewInitialize) { +RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) { + ASSERT(args.length() == 0); + ASSERT_OBJECT_SIZE( + FLAG_typed_array_max_size_in_heap + FixedTypedArrayBase::kDataOffset); + return Smi::FromInt(FLAG_typed_array_max_size_in_heap); +} + + +RUNTIME_FUNCTION(Runtime_DataViewInitialize) { HandleScope scope(isolate); ASSERT(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1); - CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset, 2); - CONVERT_ARG_HANDLE_CHECKED(Object, byte_length, 3); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset, 2); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length, 3); ASSERT(holder->GetInternalFieldCount() == v8::ArrayBufferView::kInternalFieldCount); for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { holder->SetInternalField(i, Smi::FromInt(0)); } + size_t buffer_length = 0; + size_t offset = 0; + size_t length = 0; + RUNTIME_ASSERT( + TryNumberToSize(isolate, buffer->byte_length(), &buffer_length)); + RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset, &offset)); + RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length, &length)); + + // TODO(jkummerow): When we have a "safe numerics" helper class, use it here. + // Entire range [offset, offset + length] must be in bounds. + RUNTIME_ASSERT(offset <= buffer_length); + RUNTIME_ASSERT(offset + length <= buffer_length); + // No overflow. + RUNTIME_ASSERT(offset + length >= offset); holder->set_buffer(*buffer); - ASSERT(byte_offset->IsNumber()); - ASSERT( - NumberToSize(isolate, buffer->byte_length()) >= - NumberToSize(isolate, *byte_offset) - + NumberToSize(isolate, *byte_length)); holder->set_byte_offset(*byte_offset); - ASSERT(byte_length->IsNumber()); holder->set_byte_length(*byte_length); holder->set_weak_next(buffer->weak_first_view()); @@ -1178,30 +1295,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewInitialize) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetBuffer) { - HandleScope scope(isolate); - ASSERT(args.length() == 1); - CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0); - return data_view->buffer(); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteOffset) { - HandleScope scope(isolate); - ASSERT(args.length() == 1); - CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0); - return data_view->byte_offset(); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteLength) { - HandleScope scope(isolate); - ASSERT(args.length() == 1); - CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0); - return data_view->byte_length(); -} - - inline static bool NeedToFlipBytes(bool is_little_endian) { #ifdef V8_TARGET_LITTLE_ENDIAN return !is_little_endian; @@ -1317,16 +1410,16 @@ static bool DataViewSetValue( #define DATA_VIEW_GETTER(TypeName, Type, Converter) \ - RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGet##TypeName) { \ + RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) { \ HandleScope scope(isolate); \ ASSERT(args.length() == 3); \ CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \ - CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \ + CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \ CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \ Type result; \ if (DataViewGetValue( \ isolate, holder, offset, is_little_endian, &result)) { \ - return isolate->heap()->Converter(result); \ + return *isolate->factory()->Converter(result); \ } else { \ return isolate->Throw(*isolate->factory()->NewRangeError( \ "invalid_data_view_accessor_offset", \ @@ -1334,14 +1427,14 @@ static bool DataViewSetValue( } \ } -DATA_VIEW_GETTER(Uint8, uint8_t, NumberFromUint32) -DATA_VIEW_GETTER(Int8, int8_t, NumberFromInt32) -DATA_VIEW_GETTER(Uint16, uint16_t, NumberFromUint32) -DATA_VIEW_GETTER(Int16, int16_t, NumberFromInt32) -DATA_VIEW_GETTER(Uint32, uint32_t, NumberFromUint32) -DATA_VIEW_GETTER(Int32, int32_t, NumberFromInt32) -DATA_VIEW_GETTER(Float32, float, NumberFromDouble) -DATA_VIEW_GETTER(Float64, double, NumberFromDouble) +DATA_VIEW_GETTER(Uint8, uint8_t, NewNumberFromUint) +DATA_VIEW_GETTER(Int8, int8_t, NewNumberFromInt) +DATA_VIEW_GETTER(Uint16, uint16_t, NewNumberFromUint) +DATA_VIEW_GETTER(Int16, int16_t, NewNumberFromInt) +DATA_VIEW_GETTER(Uint32, uint32_t, NewNumberFromUint) +DATA_VIEW_GETTER(Int32, int32_t, NewNumberFromInt) +DATA_VIEW_GETTER(Float32, float, NewNumber) +DATA_VIEW_GETTER(Float64, double, NewNumber) #undef DATA_VIEW_GETTER @@ -1399,12 +1492,12 @@ double DataViewConvertValue<double>(double value) { #define DATA_VIEW_SETTER(TypeName, Type) \ - RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewSet##TypeName) { \ + RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) { \ HandleScope scope(isolate); \ ASSERT(args.length() == 4); \ CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \ - CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \ - CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); \ + CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \ + CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); \ CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \ Type v = DataViewConvertValue<Type>(value->Number()); \ if (DataViewSetValue( \ @@ -1429,208 +1522,288 @@ DATA_VIEW_SETTER(Float64, double) #undef DATA_VIEW_SETTER -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) { +RUNTIME_FUNCTION(Runtime_SetInitialize) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); - Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0); + Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet(); holder->set_table(*table); return *holder; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) { +RUNTIME_FUNCTION(Runtime_SetAdd) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); - Handle<Object> key(args[1], isolate); - Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table())); - table = ObjectHashSet::Add(table, key); + CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); + Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table())); + table = OrderedHashSet::Add(table, key); holder->set_table(*table); return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) { +RUNTIME_FUNCTION(Runtime_SetHas) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); - Handle<Object> key(args[1], isolate); - Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table())); - return isolate->heap()->ToBoolean(table->Contains(*key)); + CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); + Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table())); + return isolate->heap()->ToBoolean(table->Contains(key)); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) { +RUNTIME_FUNCTION(Runtime_SetDelete) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); - Handle<Object> key(args[1], isolate); - Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table())); - table = ObjectHashSet::Remove(table, key); + CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); + Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table())); + bool was_present = false; + table = OrderedHashSet::Remove(table, key, &was_present); + holder->set_table(*table); + return isolate->heap()->ToBoolean(was_present); +} + + +RUNTIME_FUNCTION(Runtime_SetClear) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); + Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table())); + table = OrderedHashSet::Clear(table); holder->set_table(*table); return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetGetSize) { +RUNTIME_FUNCTION(Runtime_SetGetSize) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); - Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table())); + Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table())); return Smi::FromInt(table->NumberOfElements()); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) { +RUNTIME_FUNCTION(Runtime_SetIteratorInitialize) { + HandleScope scope(isolate); + ASSERT(args.length() == 3); + CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0); + CONVERT_ARG_HANDLE_CHECKED(JSSet, set, 1); + CONVERT_SMI_ARG_CHECKED(kind, 2) + RUNTIME_ASSERT(kind == JSSetIterator::kKindValues || + kind == JSSetIterator::kKindEntries); + Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table())); + holder->set_table(*table); + holder->set_index(Smi::FromInt(0)); + holder->set_kind(Smi::FromInt(kind)); + return isolate->heap()->undefined_value(); +} + + +RUNTIME_FUNCTION(Runtime_SetIteratorNext) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0); + return *JSSetIterator::Next(holder); +} + + +RUNTIME_FUNCTION(Runtime_MapInitialize) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); - Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0); + Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap(); holder->set_table(*table); return *holder; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) { +RUNTIME_FUNCTION(Runtime_MapGet) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); - Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); - Handle<Object> lookup(table->Lookup(*key), isolate); + Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); + Handle<Object> lookup(table->Lookup(key), isolate); return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_MapHas) { +RUNTIME_FUNCTION(Runtime_MapHas) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); - Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); - Handle<Object> lookup(table->Lookup(*key), isolate); + Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); + Handle<Object> lookup(table->Lookup(key), isolate); return isolate->heap()->ToBoolean(!lookup->IsTheHole()); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_MapDelete) { +RUNTIME_FUNCTION(Runtime_MapDelete) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); - Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); - Handle<Object> lookup(table->Lookup(*key), isolate); - Handle<ObjectHashTable> new_table = - ObjectHashTable::Put(table, key, isolate->factory()->the_hole_value()); + Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); + bool was_present = false; + Handle<OrderedHashMap> new_table = + OrderedHashMap::Remove(table, key, &was_present); holder->set_table(*new_table); - return isolate->heap()->ToBoolean(!lookup->IsTheHole()); + return isolate->heap()->ToBoolean(was_present); +} + + +RUNTIME_FUNCTION(Runtime_MapClear) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); + Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); + table = OrderedHashMap::Clear(table); + holder->set_table(*table); + return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) { +RUNTIME_FUNCTION(Runtime_MapSet) { HandleScope scope(isolate); ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); - Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); - Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value); + Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); + Handle<OrderedHashMap> new_table = OrderedHashMap::Put(table, key, value); holder->set_table(*new_table); return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGetSize) { +RUNTIME_FUNCTION(Runtime_MapGetSize) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); - Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); + Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); return Smi::FromInt(table->NumberOfElements()); } -static JSWeakCollection* WeakCollectionInitialize(Isolate* isolate, +RUNTIME_FUNCTION(Runtime_MapIteratorInitialize) { + HandleScope scope(isolate); + ASSERT(args.length() == 3); + CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0); + CONVERT_ARG_HANDLE_CHECKED(JSMap, map, 1); + CONVERT_SMI_ARG_CHECKED(kind, 2) + RUNTIME_ASSERT(kind == JSMapIterator::kKindKeys + || kind == JSMapIterator::kKindValues + || kind == JSMapIterator::kKindEntries); + Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table())); + holder->set_table(*table); + holder->set_index(Smi::FromInt(0)); + holder->set_kind(Smi::FromInt(kind)); + return isolate->heap()->undefined_value(); +} + + +RUNTIME_FUNCTION(Runtime_MapIteratorNext) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0); + return *JSMapIterator::Next(holder); +} + + +static Handle<JSWeakCollection> WeakCollectionInitialize( + Isolate* isolate, Handle<JSWeakCollection> weak_collection) { ASSERT(weak_collection->map()->inobject_properties() == 0); - Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0); + Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0); weak_collection->set_table(*table); - weak_collection->set_next(Smi::FromInt(0)); - return *weak_collection; + return weak_collection; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionInitialize) { +RUNTIME_FUNCTION(Runtime_WeakCollectionInitialize) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); - return WeakCollectionInitialize(isolate, weak_collection); + return *WeakCollectionInitialize(isolate, weak_collection); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionGet) { +RUNTIME_FUNCTION(Runtime_WeakCollectionGet) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); + RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); Handle<ObjectHashTable> table( ObjectHashTable::cast(weak_collection->table())); - Handle<Object> lookup(table->Lookup(*key), isolate); + RUNTIME_ASSERT(table->IsKey(*key)); + Handle<Object> lookup(table->Lookup(key), isolate); return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionHas) { +RUNTIME_FUNCTION(Runtime_WeakCollectionHas) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); + RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); Handle<ObjectHashTable> table( ObjectHashTable::cast(weak_collection->table())); - Handle<Object> lookup(table->Lookup(*key), isolate); + RUNTIME_ASSERT(table->IsKey(*key)); + Handle<Object> lookup(table->Lookup(key), isolate); return isolate->heap()->ToBoolean(!lookup->IsTheHole()); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionDelete) { +RUNTIME_FUNCTION(Runtime_WeakCollectionDelete) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); + RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); Handle<ObjectHashTable> table(ObjectHashTable::cast( weak_collection->table())); - Handle<Object> lookup(table->Lookup(*key), isolate); + RUNTIME_ASSERT(table->IsKey(*key)); + bool was_present = false; Handle<ObjectHashTable> new_table = - ObjectHashTable::Put(table, key, isolate->factory()->the_hole_value()); + ObjectHashTable::Remove(table, key, &was_present); weak_collection->set_table(*new_table); - return isolate->heap()->ToBoolean(!lookup->IsTheHole()); + return isolate->heap()->ToBoolean(was_present); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionSet) { +RUNTIME_FUNCTION(Runtime_WeakCollectionSet) { HandleScope scope(isolate); ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); - Handle<Object> value(args[2], isolate); + RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); + CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); Handle<ObjectHashTable> table( ObjectHashTable::cast(weak_collection->table())); + RUNTIME_ASSERT(table->IsKey(*key)); Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value); weak_collection->set_table(*new_table); return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) { +RUNTIME_FUNCTION(Runtime_ClassOf) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); - Object* obj = args[0]; + CONVERT_ARG_CHECKED(Object, obj, 0); if (!obj->IsJSObject()) return isolate->heap()->null_value(); return JSObject::cast(obj)->class_name(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) { +RUNTIME_FUNCTION(Runtime_GetPrototype) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); @@ -1638,45 +1811,52 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) { ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject()); do { if (obj->IsAccessCheckNeeded() && - !isolate->MayNamedAccessWrapper(Handle<JSObject>::cast(obj), - isolate->factory()->proto_string(), - v8::ACCESS_GET)) { - isolate->ReportFailedAccessCheck(JSObject::cast(*obj), v8::ACCESS_GET); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); + !isolate->MayNamedAccess(Handle<JSObject>::cast(obj), + isolate->factory()->proto_string(), + v8::ACCESS_GET)) { + isolate->ReportFailedAccessCheck(Handle<JSObject>::cast(obj), + v8::ACCESS_GET); + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); return isolate->heap()->undefined_value(); } - obj = handle(obj->GetPrototype(isolate), isolate); + obj = Object::GetPrototype(isolate, obj); } while (obj->IsJSObject() && JSObject::cast(*obj)->map()->is_hidden_prototype()); return *obj; } -static inline Object* GetPrototypeSkipHiddenPrototypes(Isolate* isolate, - Object* receiver) { - Object* current = receiver->GetPrototype(isolate); +static inline Handle<Object> GetPrototypeSkipHiddenPrototypes( + Isolate* isolate, Handle<Object> receiver) { + Handle<Object> current = Object::GetPrototype(isolate, receiver); while (current->IsJSObject() && - JSObject::cast(current)->map()->is_hidden_prototype()) { - current = current->GetPrototype(isolate); + JSObject::cast(*current)->map()->is_hidden_prototype()) { + current = Object::GetPrototype(isolate, current); } return current; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetPrototype) { +RUNTIME_FUNCTION(Runtime_SetPrototype) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); - if (FLAG_harmony_observation && obj->map()->is_observed()) { - Handle<Object> old_value( - GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate); - - Handle<Object> result = JSObject::SetPrototype(obj, prototype, true); - RETURN_IF_EMPTY_HANDLE(isolate, result); + if (obj->IsAccessCheckNeeded() && + !isolate->MayNamedAccess( + obj, isolate->factory()->proto_string(), v8::ACCESS_SET)) { + isolate->ReportFailedAccessCheck(obj, v8::ACCESS_SET); + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); + return isolate->heap()->undefined_value(); + } + if (obj->map()->is_observed()) { + Handle<Object> old_value = GetPrototypeSkipHiddenPrototypes(isolate, obj); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + JSObject::SetPrototype(obj, prototype, true)); - Handle<Object> new_value( - GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate); + Handle<Object> new_value = GetPrototypeSkipHiddenPrototypes(isolate, obj); if (!new_value->SameValue(*old_value)) { JSObject::EnqueueChangeRecord(obj, "setPrototype", isolate->factory()->proto_string(), @@ -1684,22 +1864,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetPrototype) { } return *result; } - Handle<Object> result = JSObject::SetPrototype(obj, prototype, true); - RETURN_IF_EMPTY_HANDLE(isolate, result); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + JSObject::SetPrototype(obj, prototype, true)); return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_IsInPrototypeChain) { + HandleScope shs(isolate); ASSERT(args.length() == 2); // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8). - Object* O = args[0]; - Object* V = args[1]; + CONVERT_ARG_HANDLE_CHECKED(Object, O, 0); + CONVERT_ARG_HANDLE_CHECKED(Object, V, 1); while (true) { - Object* prototype = V->GetPrototype(isolate); + Handle<Object> prototype = Object::GetPrototype(isolate, V); if (prototype->IsNull()) return isolate->heap()->false_value(); - if (O == prototype) return isolate->heap()->true_value(); + if (*O == *prototype) return isolate->heap()->true_value(); V = prototype; } } @@ -1708,6 +1890,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) { static bool CheckAccessException(Object* callback, v8::AccessType access_type) { DisallowHeapAllocation no_gc; + ASSERT(!callback->IsForeign()); if (callback->IsAccessorInfo()) { AccessorInfo* info = AccessorInfo::cast(callback); return @@ -1763,22 +1946,22 @@ static AccessCheckResult CheckPropertyAccess(Handle<JSObject> obj, if (name->AsArrayIndex(&index)) { // TODO(1095): we should traverse hidden prototype hierachy as well. if (CheckGenericAccess( - obj, obj, index, access_type, &Isolate::MayIndexedAccessWrapper)) { + obj, obj, index, access_type, &Isolate::MayIndexedAccess)) { return ACCESS_ALLOWED; } - obj->GetIsolate()->ReportFailedAccessCheck(*obj, access_type); + obj->GetIsolate()->ReportFailedAccessCheck(obj, access_type); return ACCESS_FORBIDDEN; } Isolate* isolate = obj->GetIsolate(); LookupResult lookup(isolate); - obj->LocalLookup(*name, &lookup, true); + obj->LookupOwn(name, &lookup, true); if (!lookup.IsProperty()) return ACCESS_ABSENT; Handle<JSObject> holder(lookup.holder(), isolate); if (CheckGenericAccess<Handle<Object> >( - obj, holder, name, access_type, &Isolate::MayNamedAccessWrapper)) { + obj, holder, name, access_type, &Isolate::MayNamedAccess)) { return ACCESS_ALLOWED; } @@ -1795,7 +1978,7 @@ static AccessCheckResult CheckPropertyAccess(Handle<JSObject> obj, case INTERCEPTOR: // If the object has an interceptor, try real named properties. // Overwrite the result to fetch the correct property later. - holder->LookupRealNamedProperty(*name, &lookup); + holder->LookupRealNamedProperty(name, &lookup); if (lookup.IsProperty() && lookup.IsPropertyCallbacks()) { if (CheckAccessException(lookup.GetCallbackObject(), access_type)) { return ACCESS_ALLOWED; @@ -1806,7 +1989,7 @@ static AccessCheckResult CheckPropertyAccess(Handle<JSObject> obj, break; } - isolate->ReportFailedAccessCheck(*obj, access_type); + isolate->ReportFailedAccessCheck(obj, access_type); return ACCESS_FORBIDDEN; } @@ -1824,40 +2007,43 @@ enum PropertyDescriptorIndices { }; -static Handle<Object> GetOwnProperty(Isolate* isolate, - Handle<JSObject> obj, - Handle<Name> name) { +MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate, + Handle<JSObject> obj, + Handle<Name> name) { Heap* heap = isolate->heap(); Factory* factory = isolate->factory(); // Due to some WebKit tests, we want to make sure that we do not log // more than one access failure here. AccessCheckResult access_check_result = CheckPropertyAccess(obj, name, v8::ACCESS_HAS); - RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); switch (access_check_result) { case ACCESS_FORBIDDEN: return factory->false_value(); case ACCESS_ALLOWED: break; case ACCESS_ABSENT: return factory->undefined_value(); } - PropertyAttributes attrs = obj->GetLocalPropertyAttribute(*name); + PropertyAttributes attrs = JSReceiver::GetOwnPropertyAttributes(obj, name); if (attrs == ABSENT) { - RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); return factory->undefined_value(); } ASSERT(!isolate->has_scheduled_exception()); - AccessorPair* raw_accessors = obj->GetLocalPropertyAccessorPair(*name); - Handle<AccessorPair> accessors(raw_accessors, isolate); + Handle<AccessorPair> accessors; + bool has_accessors = + JSObject::GetOwnPropertyAccessorPair(obj, name).ToHandle(&accessors); Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE); elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0)); elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0)); - elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(raw_accessors != NULL)); + elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(has_accessors)); - if (raw_accessors == NULL) { + if (!has_accessors) { elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0)); - // GetProperty does access check. - Handle<Object> value = GetProperty(isolate, obj, name); - RETURN_IF_EMPTY_HANDLE_VALUE(isolate, value, Handle<Object>::null()); + // Runtime::GetObjectProperty does access check. + Handle<Object> value; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, value, Runtime::GetObjectProperty(isolate, obj, name), + Object); elms->set(VALUE_INDEX, *value); } else { // Access checks are performed for both accessors separately. @@ -1869,14 +2055,14 @@ static Handle<Object> GetOwnProperty(Isolate* isolate, ASSERT(!isolate->has_scheduled_exception()); elms->set(GETTER_INDEX, *getter); } else { - RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); } if (!setter->IsMap() && CheckPropertyAccess(obj, name, v8::ACCESS_SET)) { ASSERT(!isolate->has_scheduled_exception()); elms->set(SETTER_INDEX, *setter); } else { - RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); } } @@ -1891,28 +2077,30 @@ static Handle<Object> GetOwnProperty(Isolate* isolate, // [false, value, Writeable, Enumerable, Configurable] // if args[1] is an accessor on args[0] // [true, GetFunction, SetFunction, Enumerable, Configurable] -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) { +RUNTIME_FUNCTION(Runtime_GetOwnProperty) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); - Handle<Object> result = GetOwnProperty(isolate, obj, name); - RETURN_IF_EMPTY_HANDLE(isolate, result); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, GetOwnProperty(isolate, obj, name)); return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) { +RUNTIME_FUNCTION(Runtime_PreventExtensions) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); - Handle<Object> result = JSObject::PreventExtensions(obj); - RETURN_IF_EMPTY_HANDLE(isolate, result); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, JSObject::PreventExtensions(obj)); return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) { +RUNTIME_FUNCTION(Runtime_IsExtensible) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSObject, obj, 0); @@ -1926,44 +2114,46 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) { +RUNTIME_FUNCTION(Runtime_RegExpCompile) { HandleScope scope(isolate); ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0); CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); CONVERT_ARG_HANDLE_CHECKED(String, flags, 2); - Handle<Object> result = RegExpImpl::Compile(re, pattern, flags); - RETURN_IF_EMPTY_HANDLE(isolate, result); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, RegExpImpl::Compile(re, pattern, flags)); return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) { +RUNTIME_FUNCTION(Runtime_CreateApiFunction) { HandleScope scope(isolate); - ASSERT(args.length() == 1); + ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0); - return *isolate->factory()->CreateApiFunction(data); + CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); + return *isolate->factory()->CreateApiFunction(data, prototype); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) { +RUNTIME_FUNCTION(Runtime_IsTemplate) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); - Object* arg = args[0]; + CONVERT_ARG_HANDLE_CHECKED(Object, arg, 0); bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo(); return isolate->heap()->ToBoolean(result); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) { +RUNTIME_FUNCTION(Runtime_GetTemplateField) { SealHandleScope shs(isolate); ASSERT(args.length() == 2); CONVERT_ARG_CHECKED(HeapObject, templ, 0); - CONVERT_SMI_ARG_CHECKED(index, 1) + CONVERT_SMI_ARG_CHECKED(index, 1); int offset = index * kPointerSize + HeapObject::kHeaderSize; InstanceType type = templ->map()->instance_type(); - RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE || - type == OBJECT_TEMPLATE_INFO_TYPE); + RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE || + type == OBJECT_TEMPLATE_INFO_TYPE); RUNTIME_ASSERT(offset > 0); if (type == FUNCTION_TEMPLATE_INFO_TYPE) { RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize); @@ -1974,38 +2164,40 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_DisableAccessChecks) { + HandleScope scope(isolate); ASSERT(args.length() == 1); - CONVERT_ARG_CHECKED(HeapObject, object, 0); - Map* old_map = object->map(); + CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0); + Handle<Map> old_map(object->map()); bool needs_access_checks = old_map->is_access_check_needed(); if (needs_access_checks) { // Copy map so it won't interfere constructor's initial map. - Map* new_map; - MaybeObject* maybe_new_map = old_map->Copy(); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; - + Handle<Map> new_map = Map::Copy(old_map); new_map->set_is_access_check_needed(false); - object->set_map(new_map); + if (object->IsJSObject()) { + JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map); + } else { + object->set_map(*new_map); + } } return isolate->heap()->ToBoolean(needs_access_checks); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_EnableAccessChecks) { + HandleScope scope(isolate); ASSERT(args.length() == 1); - CONVERT_ARG_CHECKED(HeapObject, object, 0); - Map* old_map = object->map(); + CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0); + Handle<Map> old_map(object->map()); if (!old_map->is_access_check_needed()) { // Copy map so it won't interfere constructor's initial map. - Map* new_map; - MaybeObject* maybe_new_map = old_map->Copy(); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; - + Handle<Map> new_map = Map::Copy(old_map); new_map->set_is_access_check_needed(true); - object->set_map(new_map); + if (object->IsJSObject()) { + JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map); + } else { + object->set_map(*new_map); + } } return isolate->heap()->undefined_value(); } @@ -2021,7 +2213,7 @@ static Handle<Object> InstantiateAccessorComponent(Isolate* isolate, } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAccessorProperty) { +RUNTIME_FUNCTION(Runtime_SetAccessorProperty) { HandleScope scope(isolate); ASSERT(args.length() == 6); CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); @@ -2030,6 +2222,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAccessorProperty) { CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3); CONVERT_SMI_ARG_CHECKED(attribute, 4); CONVERT_SMI_ARG_CHECKED(access_control, 5); + RUNTIME_ASSERT(getter->IsUndefined() || getter->IsFunctionTemplateInfo()); + RUNTIME_ASSERT(setter->IsUndefined() || setter->IsFunctionTemplateInfo()); + RUNTIME_ASSERT(PropertyDetails::AttributesField::is_valid( + static_cast<PropertyAttributes>(attribute))); JSObject::DefineAccessor(object, name, InstantiateAccessorComponent(isolate, getter), @@ -2040,26 +2236,22 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAccessorProperty) { } -static Failure* ThrowRedeclarationError(Isolate* isolate, - const char* type, - Handle<String> name) { +static Object* ThrowRedeclarationError(Isolate* isolate, Handle<String> name) { HandleScope scope(isolate); - Handle<Object> type_handle = - isolate->factory()->NewStringFromAscii(CStrVector(type)); - Handle<Object> args[2] = { type_handle, name }; - Handle<Object> error = - isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2)); + Handle<Object> args[1] = { name }; + Handle<Object> error = isolate->factory()->NewTypeError( + "var_redeclaration", HandleVector(args, 1)); return isolate->Throw(*error); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { +RUNTIME_FUNCTION(RuntimeHidden_DeclareGlobals) { HandleScope scope(isolate); ASSERT(args.length() == 3); Handle<GlobalObject> global = Handle<GlobalObject>( isolate->context()->global_object()); - Handle<Context> context = args.at<Context>(0); + CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1); CONVERT_SMI_ARG_CHECKED(flags, 2); @@ -2081,19 +2273,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { if (is_var || is_const) { // Lookup the property in the global object, and don't set the // value of the variable if the property is already there. - // Do the lookup locally only, see ES5 erratum. + // Do the lookup own properties only, see ES5 erratum. LookupResult lookup(isolate); - if (FLAG_es52_globals) { - global->LocalLookup(*name, &lookup, true); - } else { - global->Lookup(*name, &lookup); - } + global->LookupOwn(name, &lookup, true); if (lookup.IsFound()) { // We found an existing property. Unless it was an interceptor // that claims the property is absent, skip this declaration. if (!lookup.IsInterceptor()) continue; - PropertyAttributes attributes = global->GetPropertyAttribute(*name); - if (attributes != ABSENT) continue; + if (JSReceiver::GetPropertyAttributes(global, name) != ABSENT) continue; // Fall-through and introduce the absent property by using // SetProperty. } @@ -2108,7 +2295,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { } LookupResult lookup(isolate); - global->LocalLookup(*name, &lookup, true); + global->LookupOwn(name, &lookup, true); // Compute the property attributes. According to ECMA-262, // the property must be non-configurable except in eval. @@ -2122,29 +2309,30 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { attr |= READ_ONLY; } - LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags); + StrictMode strict_mode = DeclareGlobalsStrictMode::decode(flags); if (!lookup.IsFound() || is_function) { - // If the local property exists, check that we can reconfigure it + // If the own property exists, check that we can reconfigure it // as required for function declarations. if (lookup.IsFound() && lookup.IsDontDelete()) { if (lookup.IsReadOnly() || lookup.IsDontEnum() || lookup.IsPropertyCallbacks()) { - return ThrowRedeclarationError(isolate, "function", name); + return ThrowRedeclarationError(isolate, name); } // If the existing property is not configurable, keep its attributes. attr = lookup.GetAttributes(); } // Define or redefine own property. - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::SetLocalPropertyIgnoreAttributes( + RETURN_FAILURE_ON_EXCEPTION(isolate, + JSObject::SetOwnPropertyIgnoreAttributes( global, name, value, static_cast<PropertyAttributes>(attr))); } else { // Do a [[Put]] on the existing (own) property. - RETURN_IF_EMPTY_HANDLE(isolate, + RETURN_FAILURE_ON_EXCEPTION( + isolate, JSObject::SetProperty( global, name, value, static_cast<PropertyAttributes>(attr), - language_mode == CLASSIC_MODE ? kNonStrictMode : kStrictMode)); + strict_mode)); } } @@ -2153,20 +2341,20 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { +RUNTIME_FUNCTION(RuntimeHidden_DeclareContextSlot) { HandleScope scope(isolate); ASSERT(args.length() == 4); // Declarations are always made in a function or native context. In the // case of eval code, the context passed is the context of the caller, // which may be some nested context and not the declaration context. - RUNTIME_ASSERT(args[0]->IsContext()); - Handle<Context> context(Context::cast(args[0])->declaration_context()); - - Handle<String> name(String::cast(args[1])); - PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2)); + CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 0); + Handle<Context> context(context_arg->declaration_context()); + CONVERT_ARG_HANDLE_CHECKED(String, name, 1); + CONVERT_SMI_ARG_CHECKED(mode_arg, 2); + PropertyAttributes mode = static_cast<PropertyAttributes>(mode_arg); RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE); - Handle<Object> initial_value(args[3], isolate); + CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 3); int index; PropertyAttributes attributes; @@ -2182,8 +2370,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) { // Functions are not read-only. ASSERT(mode != READ_ONLY || initial_value->IsTheHole()); - const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var"; - return ThrowRedeclarationError(isolate, type, name); + return ThrowRedeclarationError(isolate, name); } // Initialize it if necessary. @@ -2198,10 +2385,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { // Slow case: The property is in the context extension object of a // function context or the global object of a native context. Handle<JSObject> object = Handle<JSObject>::cast(holder); - RETURN_IF_EMPTY_HANDLE( + RETURN_FAILURE_ON_EXCEPTION( isolate, - JSReceiver::SetProperty(object, name, initial_value, mode, - kNonStrictMode)); + JSReceiver::SetProperty(object, name, initial_value, mode, SLOPPY)); } } @@ -2224,7 +2410,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { // Declare the property by setting it to the initial value if provided, // or undefined, and use the correct mode (e.g. READ_ONLY attribute for // constant declarations). - ASSERT(!JSReceiver::HasLocalProperty(object, name)); + ASSERT(!JSReceiver::HasOwnProperty(object, name)); Handle<Object> value(isolate->heap()->undefined_value(), isolate); if (*initial_value != NULL) value = initial_value; // Declaring a const context slot is a conflicting declaration if @@ -2236,18 +2422,18 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { if (initial_value->IsTheHole() && !object->IsJSContextExtensionObject()) { LookupResult lookup(isolate); - object->Lookup(*name, &lookup); + object->Lookup(name, &lookup); if (lookup.IsPropertyCallbacks()) { - return ThrowRedeclarationError(isolate, "const", name); + return ThrowRedeclarationError(isolate, name); } } if (object->IsJSGlobalObject()) { // Define own property on the global object. - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::SetLocalPropertyIgnoreAttributes(object, name, value, mode)); + RETURN_FAILURE_ON_EXCEPTION(isolate, + JSObject::SetOwnPropertyIgnoreAttributes(object, name, value, mode)); } else { - RETURN_IF_EMPTY_HANDLE(isolate, - JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode)); + RETURN_FAILURE_ON_EXCEPTION(isolate, + JSReceiver::SetProperty(object, name, value, mode, SLOPPY)); } } @@ -2255,7 +2441,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { +RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) { HandleScope scope(isolate); // args[0] == name // args[1] == language_mode @@ -2267,35 +2453,34 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { bool assign = args.length() == 3; CONVERT_ARG_HANDLE_CHECKED(String, name, 0); - RUNTIME_ASSERT(args[1]->IsSmi()); - CONVERT_LANGUAGE_MODE_ARG(language_mode, 1); - StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE) - ? kNonStrictMode : kStrictMode; + CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 1); // According to ECMA-262, section 12.2, page 62, the property must // not be deletable. PropertyAttributes attributes = DONT_DELETE; - // Lookup the property locally in the global object. If it isn't + // Lookup the property as own on the global object. If it isn't // there, there is a property with this name in the prototype chain. // We follow Safari and Firefox behavior and only set the property - // locally if there is an explicit initialization value that we have + // if there is an explicit initialization value that we have // to assign to the property. // Note that objects can have hidden prototypes, so we need to traverse - // the whole chain of hidden prototypes to do a 'local' lookup. + // the whole chain of hidden prototypes to do an 'own' lookup. LookupResult lookup(isolate); - isolate->context()->global_object()->LocalLookup(*name, &lookup, true); + isolate->context()->global_object()->LookupOwn(name, &lookup, true); if (lookup.IsInterceptor()) { + Handle<JSObject> holder(lookup.holder()); PropertyAttributes intercepted = - lookup.holder()->GetPropertyAttribute(*name); + JSReceiver::GetPropertyAttributes(holder, name); if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { // Found an interceptor that's not read only. if (assign) { CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); - Handle<Object> result = JSObject::SetPropertyForResult( - handle(lookup.holder()), &lookup, name, value, attributes, - strict_mode_flag); - RETURN_IF_EMPTY_HANDLE(isolate, result); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + JSObject::SetPropertyForResult( + holder, &lookup, name, value, attributes, strict_mode)); return *result; } else { return isolate->heap()->undefined_value(); @@ -2306,23 +2491,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { if (assign) { CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); Handle<GlobalObject> global(isolate->context()->global_object()); - Handle<Object> result = JSReceiver::SetProperty( - global, name, value, attributes, strict_mode_flag); - RETURN_IF_EMPTY_HANDLE(isolate, result); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + JSReceiver::SetProperty(global, name, value, attributes, strict_mode)); return *result; } return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) { +RUNTIME_FUNCTION(RuntimeHidden_InitializeConstGlobal) { SealHandleScope shs(isolate); // All constants are declared with an initial value. The name // of the constant is the first argument and the initial value // is the second. RUNTIME_ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(String, name, 0); - Handle<Object> value = args.at<Object>(1); + CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); // Get the current global object from top. GlobalObject* global = isolate->context()->global_object(); @@ -2332,20 +2518,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) { PropertyAttributes attributes = static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY); - // Lookup the property locally in the global object. If it isn't + // Lookup the property as own on the global object. If it isn't // there, we add the property and take special precautions to always - // add it as a local property even in case of callbacks in the - // prototype chain (this rules out using SetProperty). - // We use SetLocalPropertyIgnoreAttributes instead + // add it even in case of callbacks in the prototype chain (this rules + // out using SetProperty). We use SetOwnPropertyIgnoreAttributes instead LookupResult lookup(isolate); - global->LocalLookup(*name, &lookup); + global->LookupOwn(name, &lookup); if (!lookup.IsFound()) { HandleScope handle_scope(isolate); Handle<GlobalObject> global(isolate->context()->global_object()); - RETURN_IF_EMPTY_HANDLE( + RETURN_FAILURE_ON_EXCEPTION( isolate, - JSObject::SetLocalPropertyIgnoreAttributes(global, name, value, - attributes)); + JSObject::SetOwnPropertyIgnoreAttributes(global, name, value, + attributes)); return *value; } @@ -2358,11 +2543,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) { // BUG 1213575: Handle the case where we have to set a read-only // property through an interceptor and only do it if it's // uninitialized, e.g. the hole. Nirk... - // Passing non-strict mode because the property is writable. - RETURN_IF_EMPTY_HANDLE( + // Passing sloppy mode because the property is writable. + RETURN_FAILURE_ON_EXCEPTION( isolate, - JSReceiver::SetProperty(global, name, value, attributes, - kNonStrictMode)); + JSReceiver::SetProperty(global, name, value, attributes, SLOPPY)); return *value; } @@ -2372,7 +2556,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) { // Strict mode handling not needed (const is disallowed in strict mode). if (lookup.IsField()) { FixedArray* properties = global->properties(); - int index = lookup.GetFieldIndex().field_index(); + int index = lookup.GetFieldIndex().outobject_array_index(); if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) { properties->set(index, *value); } @@ -2393,18 +2577,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { +RUNTIME_FUNCTION(RuntimeHidden_InitializeConstContextSlot) { HandleScope scope(isolate); ASSERT(args.length() == 3); - Handle<Object> value(args[0], isolate); + CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); ASSERT(!value->IsTheHole()); - // Initializations are always done in a function or native context. - RUNTIME_ASSERT(args[1]->IsContext()); - Handle<Context> context(Context::cast(args[1])->declaration_context()); - - Handle<String> name(String::cast(args[2])); + CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 1); + Handle<Context> context(context_arg->declaration_context()); + CONVERT_ARG_HANDLE_CHECKED(String, name, 2); int index; PropertyAttributes attributes; @@ -2430,9 +2612,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { Handle<JSObject> global = Handle<JSObject>( isolate->context()->global_object()); // Strict mode not needed (const disallowed in strict mode). - RETURN_IF_EMPTY_HANDLE( + RETURN_FAILURE_ON_EXCEPTION( isolate, - JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode)); + JSReceiver::SetProperty(global, name, value, NONE, SLOPPY)); return *value; } @@ -2457,15 +2639,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { // Set it if it hasn't been set before. NOTE: We cannot use // GetProperty() to get the current value as it 'unholes' the value. LookupResult lookup(isolate); - object->LocalLookupRealNamedProperty(*name, &lookup); + object->LookupOwnRealNamedProperty(name, &lookup); ASSERT(lookup.IsFound()); // the property was declared ASSERT(lookup.IsReadOnly()); // and it was declared as read-only if (lookup.IsField()) { FixedArray* properties = object->properties(); - int index = lookup.GetFieldIndex().field_index(); - if (properties->get(index)->IsTheHole()) { - properties->set(index, *value); + FieldIndex index = lookup.GetFieldIndex(); + ASSERT(!index.is_inobject()); + if (properties->get(index.outobject_array_index())->IsTheHole()) { + properties->set(index.outobject_array_index(), *value); } } else if (lookup.IsNormal()) { if (object->GetNormalizedProperty(&lookup)->IsTheHole()) { @@ -2481,10 +2664,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { // read-only property. if ((attributes & READ_ONLY) == 0) { // Strict mode not needed (const disallowed in strict mode). - RETURN_IF_EMPTY_HANDLE( + RETURN_FAILURE_ON_EXCEPTION( isolate, - JSReceiver::SetProperty(object, name, value, attributes, - kNonStrictMode)); + JSReceiver::SetProperty(object, name, value, attributes, SLOPPY)); } } @@ -2492,20 +2674,21 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { } -RUNTIME_FUNCTION(MaybeObject*, - Runtime_OptimizeObjectForAddingMultipleProperties) { +RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); CONVERT_SMI_ARG_CHECKED(properties, 1); - if (object->HasFastProperties()) { + // Conservative upper limit to prevent fuzz tests from going OOM. + RUNTIME_ASSERT(properties <= 100000); + if (object->HasFastProperties() && !object->IsJSGlobalProxy()) { JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties); } return *object; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) { +RUNTIME_FUNCTION(RuntimeHidden_RegExpExec) { HandleScope scope(isolate); ASSERT(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); @@ -2517,54 +2700,37 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) { RUNTIME_ASSERT(index >= 0); RUNTIME_ASSERT(index <= subject->length()); isolate->counters()->regexp_entry_runtime()->Increment(); - Handle<Object> result = RegExpImpl::Exec(regexp, - subject, - index, - last_match_info); - RETURN_IF_EMPTY_HANDLE(isolate, result); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + RegExpImpl::Exec(regexp, subject, index, last_match_info)); return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_RegExpConstructResult) { + HandleScope handle_scope(isolate); ASSERT(args.length() == 3); - CONVERT_SMI_ARG_CHECKED(elements_count, 0); - if (elements_count < 0 || - elements_count > FixedArray::kMaxLength || - !Smi::IsValid(elements_count)) { - return isolate->ThrowIllegalOperation(); - } - Object* new_object; - { MaybeObject* maybe_new_object = - isolate->heap()->AllocateFixedArray(elements_count); - if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object; - } - FixedArray* elements = FixedArray::cast(new_object); - { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw( - JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE); - if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object; - } - { - DisallowHeapAllocation no_gc; - HandleScope scope(isolate); - reinterpret_cast<HeapObject*>(new_object)-> - set_map(isolate->native_context()->regexp_result_map()); - } - JSArray* array = JSArray::cast(new_object); - array->set_properties(isolate->heap()->empty_fixed_array()); - array->set_elements(elements); - array->set_length(Smi::FromInt(elements_count)); + CONVERT_SMI_ARG_CHECKED(size, 0); + RUNTIME_ASSERT(size >= 0 && size <= FixedArray::kMaxLength); + CONVERT_ARG_HANDLE_CHECKED(Object, index, 1); + CONVERT_ARG_HANDLE_CHECKED(Object, input, 2); + Handle<FixedArray> elements = isolate->factory()->NewFixedArray(size); + Handle<Map> regexp_map(isolate->native_context()->regexp_result_map()); + Handle<JSObject> object = + isolate->factory()->NewJSObjectFromMap(regexp_map, NOT_TENURED, false); + Handle<JSArray> array = Handle<JSArray>::cast(object); + array->set_elements(*elements); + array->set_length(Smi::FromInt(size)); // Write in-object properties after the length of the array. - array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]); - array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]); - return array; + array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, *index); + array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, *input); + return *array; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) { +RUNTIME_FUNCTION(Runtime_RegExpInitializeObject) { HandleScope scope(isolate); - DisallowHeapAllocation no_allocation; ASSERT(args.length() == 5); CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); CONVERT_ARG_HANDLE_CHECKED(String, source, 1); @@ -2607,24 +2773,27 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) { static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); Handle<Object> zero(Smi::FromInt(0), isolate); Factory* factory = isolate->factory(); - CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes( - regexp, factory->source_string(), source, final)); - CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes( - regexp, factory->global_string(), global, final)); - CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes( - regexp, factory->ignore_case_string(), ignoreCase, final)); - CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes( - regexp, factory->multiline_string(), multiline, final)); - CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes( - regexp, factory->last_index_string(), zero, writable)); + JSObject::SetOwnPropertyIgnoreAttributes( + regexp, factory->source_string(), source, final).Check(); + JSObject::SetOwnPropertyIgnoreAttributes( + regexp, factory->global_string(), global, final).Check(); + JSObject::SetOwnPropertyIgnoreAttributes( + regexp, factory->ignore_case_string(), ignoreCase, final).Check(); + JSObject::SetOwnPropertyIgnoreAttributes( + regexp, factory->multiline_string(), multiline, final).Check(); + JSObject::SetOwnPropertyIgnoreAttributes( + regexp, factory->last_index_string(), zero, writable).Check(); return *regexp; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) { +RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0); + Object* length = prototype->length(); + RUNTIME_ASSERT(length->IsSmi() && Smi::cast(length)->value() == 0); + RUNTIME_ASSERT(prototype->HasFastSmiOrObjectElements()); // This is necessary to enable fast checks for absence of elements // on Array.prototype and below. prototype->set_elements(isolate->heap()->empty_fixed_array()); @@ -2632,28 +2801,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) { } -static Handle<JSFunction> InstallBuiltin(Isolate* isolate, - Handle<JSObject> holder, - const char* name, - Builtins::Name builtin_name) { +static void InstallBuiltin(Isolate* isolate, + Handle<JSObject> holder, + const char* name, + Builtins::Name builtin_name) { Handle<String> key = isolate->factory()->InternalizeUtf8String(name); Handle<Code> code(isolate->builtins()->builtin(builtin_name)); Handle<JSFunction> optimized = - isolate->factory()->NewFunction(key, - JS_OBJECT_TYPE, - JSObject::kHeaderSize, - code, - false); + isolate->factory()->NewFunctionWithoutPrototype(key, code); optimized->shared()->DontAdaptArguments(); - JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode); - return optimized; + JSReceiver::SetProperty(holder, key, optimized, NONE, STRICT).Assert(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) { +RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) { HandleScope scope(isolate); - ASSERT(args.length() == 1); - CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0); + ASSERT(args.length() == 0); + Handle<JSObject> holder = + isolate->factory()->NewJSObject(isolate->object_function()); InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop); InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush); @@ -2667,49 +2832,43 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsCallable) { - SealHandleScope shs(isolate); - ASSERT(args.length() == 1); - CONVERT_ARG_CHECKED(Object, obj, 0); - return isolate->heap()->ToBoolean(obj->IsCallable()); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsClassicModeFunction) { +RUNTIME_FUNCTION(Runtime_IsSloppyModeFunction) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSReceiver, callable, 0); if (!callable->IsJSFunction()) { HandleScope scope(isolate); - bool threw = false; - Handle<Object> delegate = Execution::TryGetFunctionDelegate( - isolate, Handle<JSReceiver>(callable), &threw); - if (threw) return Failure::Exception(); + Handle<Object> delegate; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, delegate, + Execution::TryGetFunctionDelegate( + isolate, Handle<JSReceiver>(callable))); callable = JSFunction::cast(*delegate); } JSFunction* function = JSFunction::cast(callable); SharedFunctionInfo* shared = function->shared(); - return isolate->heap()->ToBoolean(shared->is_classic_mode()); + return isolate->heap()->ToBoolean(shared->strict_mode() == SLOPPY); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) { +RUNTIME_FUNCTION(Runtime_GetDefaultReceiver) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSReceiver, callable, 0); if (!callable->IsJSFunction()) { HandleScope scope(isolate); - bool threw = false; - Handle<Object> delegate = Execution::TryGetFunctionDelegate( - isolate, Handle<JSReceiver>(callable), &threw); - if (threw) return Failure::Exception(); + Handle<Object> delegate; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, delegate, + Execution::TryGetFunctionDelegate( + isolate, Handle<JSReceiver>(callable))); callable = JSFunction::cast(*delegate); } JSFunction* function = JSFunction::cast(callable); SharedFunctionInfo* shared = function->shared(); - if (shared->native() || !shared->is_classic_mode()) { + if (shared->native() || shared->strict_mode() == STRICT) { return isolate->heap()->undefined_value(); } // Returns undefined for strict or native functions, or @@ -2721,13 +2880,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) { +RUNTIME_FUNCTION(RuntimeHidden_MaterializeRegExpLiteral) { HandleScope scope(isolate); ASSERT(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); - int index = args.smi_at(1); - Handle<String> pattern = args.at<String>(2); - Handle<String> flags = args.at<String>(3); + CONVERT_SMI_ARG_CHECKED(index, 1); + CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2); + CONVERT_ARG_HANDLE_CHECKED(String, flags, 3); // Get the RegExp function from the context in the literals array. // This is the RegExp function from the context in which the @@ -2738,20 +2897,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) { Handle<JSFunction>( JSFunction::NativeContextFromLiterals(*literals)->regexp_function()); // Compute the regular expression literal. - bool has_pending_exception; - Handle<Object> regexp = - RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags, - &has_pending_exception); - if (has_pending_exception) { - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } + Handle<Object> regexp; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, regexp, + RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags)); literals->set(index, *regexp); return *regexp; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) { +RUNTIME_FUNCTION(Runtime_FunctionGetName) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); @@ -2760,7 +2915,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) { +RUNTIME_FUNCTION(Runtime_FunctionSetName) { SealHandleScope shs(isolate); ASSERT(args.length() == 2); @@ -2771,7 +2926,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) { +RUNTIME_FUNCTION(Runtime_FunctionNameShouldPrintAsAnonymous) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSFunction, f, 0); @@ -2780,7 +2935,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) { +RUNTIME_FUNCTION(Runtime_FunctionMarkNameShouldPrintAsAnonymous) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSFunction, f, 0); @@ -2789,7 +2944,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsGenerator) { +RUNTIME_FUNCTION(Runtime_FunctionIsGenerator) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSFunction, f, 0); @@ -2797,18 +2952,18 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsGenerator) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) { +RUNTIME_FUNCTION(Runtime_FunctionRemovePrototype) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSFunction, f, 0); - f->RemovePrototype(); + RUNTIME_ASSERT(f->RemovePrototype()); return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) { +RUNTIME_FUNCTION(Runtime_FunctionGetScript) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -2816,11 +2971,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) { Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate); if (!script->IsScript()) return isolate->heap()->undefined_value(); - return *GetScriptWrapper(Handle<Script>::cast(script)); + return *Script::GetWrapper(Handle<Script>::cast(script)); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) { +RUNTIME_FUNCTION(Runtime_FunctionGetSourceCode) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -2830,7 +2985,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) { +RUNTIME_FUNCTION(Runtime_FunctionGetScriptSourcePosition) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); @@ -2840,7 +2995,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) { +RUNTIME_FUNCTION(Runtime_FunctionGetPositionForOffset) { SealHandleScope shs(isolate); ASSERT(args.length() == 2); @@ -2854,7 +3009,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) { +RUNTIME_FUNCTION(Runtime_FunctionSetInstanceClassName) { SealHandleScope shs(isolate); ASSERT(args.length() == 2); @@ -2865,72 +3020,32 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) { +RUNTIME_FUNCTION(Runtime_FunctionSetLength) { SealHandleScope shs(isolate); ASSERT(args.length() == 2); CONVERT_ARG_CHECKED(JSFunction, fun, 0); CONVERT_SMI_ARG_CHECKED(length, 1); + RUNTIME_ASSERT((length & 0xC0000000) == 0xC0000000 || + (length & 0xC0000000) == 0x0); fun->shared()->set_length(length); return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) { +RUNTIME_FUNCTION(Runtime_FunctionSetPrototype) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); - ASSERT(fun->should_have_prototype()); + RUNTIME_ASSERT(fun->should_have_prototype()); Accessors::FunctionSetPrototype(fun, value); return args[0]; // return TOS } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) { - SealHandleScope shs(isolate); - RUNTIME_ASSERT(args.length() == 1); - CONVERT_ARG_CHECKED(JSFunction, function, 0); - - String* name = isolate->heap()->prototype_string(); - - if (function->HasFastProperties()) { - // Construct a new field descriptor with updated attributes. - DescriptorArray* instance_desc = function->map()->instance_descriptors(); - - int index = instance_desc->SearchWithCache(name, function->map()); - ASSERT(index != DescriptorArray::kNotFound); - PropertyDetails details = instance_desc->GetDetails(index); - - CallbacksDescriptor new_desc(name, - instance_desc->GetValue(index), - static_cast<PropertyAttributes>(details.attributes() | READ_ONLY)); - - // Create a new map featuring the new field descriptors array. - Map* new_map; - MaybeObject* maybe_map = - function->map()->CopyReplaceDescriptor( - instance_desc, &new_desc, index, OMIT_TRANSITION); - if (!maybe_map->To(&new_map)) return maybe_map; - - function->set_map(new_map); - } else { // Dictionary properties. - // Directly manipulate the property details. - int entry = function->property_dictionary()->FindEntry(name); - ASSERT(entry != NameDictionary::kNotFound); - PropertyDetails details = function->property_dictionary()->DetailsAt(entry); - PropertyDetails new_details( - static_cast<PropertyAttributes>(details.attributes() | READ_ONLY), - details.type(), - details.dictionary_index()); - function->property_dictionary()->DetailsAtPut(entry, new_details); - } - return function; -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) { +RUNTIME_FUNCTION(Runtime_FunctionIsAPIFunction) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); @@ -2939,7 +3054,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) { +RUNTIME_FUNCTION(Runtime_FunctionIsBuiltin) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); @@ -2948,21 +3063,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { +RUNTIME_FUNCTION(Runtime_SetCode) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0); - Handle<Object> code = args.at<Object>(1); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, source, 1); - if (code->IsNull()) return *target; - RUNTIME_ASSERT(code->IsJSFunction()); - Handle<JSFunction> source = Handle<JSFunction>::cast(code); Handle<SharedFunctionInfo> target_shared(target->shared()); Handle<SharedFunctionInfo> source_shared(source->shared()); + RUNTIME_ASSERT(!source_shared->bound()); - if (!JSFunction::EnsureCompiled(source, KEEP_EXCEPTION)) { - return Failure::Exception(); + if (!Compiler::EnsureCompiled(source, KEEP_EXCEPTION)) { + return isolate->heap()->exception(); } // Mark both, the source and the target, as un-flushable because the @@ -2977,6 +3090,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { target_shared->ReplaceCode(source_shared->code()); target_shared->set_scope_info(source_shared->scope_info()); target_shared->set_length(source_shared->length()); + target_shared->set_feedback_vector(source_shared->feedback_vector()); target_shared->set_formal_parameter_count( source_shared->formal_parameter_count()); target_shared->set_script(source_shared->script()); @@ -2986,6 +3100,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { bool was_native = target_shared->native(); target_shared->set_compiler_hints(source_shared->compiler_hints()); target_shared->set_native(was_native); + target_shared->set_profiler_ticks(source_shared->profiler_ticks()); // Set the code of the target function. target->ReplaceCode(source_shared->code()); @@ -3014,32 +3129,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) { - HandleScope scope(isolate); - ASSERT(args.length() == 2); - CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); - CONVERT_SMI_ARG_CHECKED(num, 1); - RUNTIME_ASSERT(num >= 0); - // If objects constructed from this function exist then changing - // 'estimated_nof_properties' is dangerous since the previous value might - // have been compiled into the fast construct stub. Moreover, the inobject - // slack tracking logic might have adjusted the previous value, so even - // passing the same value is risky. - if (!func->shared()->live_objects_may_exist()) { - func->shared()->set_expected_nof_properties(num); - if (func->has_initial_map()) { - Handle<Map> new_initial_map = - func->GetIsolate()->factory()->CopyMap( - Handle<Map>(func->initial_map())); - new_initial_map->set_unused_property_fields(num); - func->set_initial_map(*new_initial_map); - } - } - return isolate->heap()->undefined_value(); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSGeneratorObject) { +RUNTIME_FUNCTION(RuntimeHidden_CreateJSGeneratorObject) { HandleScope scope(isolate); ASSERT(args.length() == 0); @@ -3065,10 +3155,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSGeneratorObject) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SuspendJSGeneratorObject) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_SuspendJSGeneratorObject) { + HandleScope handle_scope(isolate); ASSERT(args.length() == 1); - CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0); + CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0); JavaScriptFrameIterator stack_iterator(isolate); JavaScriptFrame* frame = stack_iterator.frame(); @@ -3097,11 +3187,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SuspendJSGeneratorObject) { ASSERT(!frame->HasHandler()); } else { int stack_handler_index = -1; - MaybeObject* alloc = isolate->heap()->AllocateFixedArray(operands_count); - FixedArray* operand_stack; - if (!alloc->To(&operand_stack)) return alloc; - frame->SaveOperandStack(operand_stack, &stack_handler_index); - generator_object->set_operand_stack(operand_stack); + Handle<FixedArray> operand_stack = + isolate->factory()->NewFixedArray(operands_count); + frame->SaveOperandStack(*operand_stack, &stack_handler_index); + generator_object->set_operand_stack(*operand_stack); generator_object->set_stack_handler_index(stack_handler_index); } @@ -3116,7 +3205,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SuspendJSGeneratorObject) { // inlined into GeneratorNext and GeneratorThrow. EmitGeneratorResumeResume is // called in any case, as it needs to reconstruct the stack frame and make space // for arguments and operands. -RUNTIME_FUNCTION(MaybeObject*, Runtime_ResumeJSGeneratorObject) { +RUNTIME_FUNCTION(RuntimeHidden_ResumeJSGeneratorObject) { SealHandleScope shs(isolate); ASSERT(args.length() == 3); CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0); @@ -3128,13 +3217,17 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ResumeJSGeneratorObject) { ASSERT_EQ(frame->function(), generator_object->function()); ASSERT(frame->function()->is_compiled()); - STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0); - STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0); + STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0); + STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0); Address pc = generator_object->function()->code()->instruction_start(); int offset = generator_object->continuation(); ASSERT(offset > 0); frame->set_pc(pc + offset); + if (FLAG_enable_ool_constant_pool) { + frame->set_constant_pool( + generator_object->function()->code()->constant_pool()); + } generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting); FixedArray* operand_stack = generator_object->operand_stack(); @@ -3160,7 +3253,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ResumeJSGeneratorObject) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowGeneratorStateError) { +RUNTIME_FUNCTION(RuntimeHidden_ThrowGeneratorStateError) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); @@ -3173,41 +3266,33 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowGeneratorStateError) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ObjectFreeze) { +RUNTIME_FUNCTION(Runtime_ObjectFreeze) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); - Handle<Object> result = JSObject::Freeze(object); - RETURN_IF_EMPTY_HANDLE(isolate, result); - return *result; -} + // %ObjectFreeze is a fast path and these cases are handled elsewhere. + RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() && + !object->map()->is_observed() && + !object->IsJSProxy()); -MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate, - Object* char_code) { - if (char_code->IsNumber()) { - return isolate->heap()->LookupSingleCharacterStringFromCode( - NumberToUint32(char_code) & 0xffff); - } - return isolate->heap()->empty_string(); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object)); + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_StringCharCodeAt) { + HandleScope handle_scope(isolate); ASSERT(args.length() == 2); - CONVERT_ARG_CHECKED(String, subject, 0); + CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]); // Flatten the string. If someone wants to get a char at an index // in a cons string, it is likely that more indices will be // accessed. - Object* flat; - { MaybeObject* maybe_flat = subject->TryFlatten(); - if (!maybe_flat->ToObject(&flat)) return maybe_flat; - } - subject = String::cast(flat); + subject = String::Flatten(subject); if (i >= static_cast<uint32_t>(subject->length())) { return isolate->heap()->nan_value(); @@ -3217,10 +3302,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_CharFromCode) { + HandleScope handlescope(isolate); ASSERT(args.length() == 1); - return CharFromCode(isolate, args[0]); + if (args[0]->IsNumber()) { + CONVERT_NUMBER_CHECKED(uint32_t, code, Uint32, args[0]); + code &= 0xffff; + return *isolate->factory()->LookupSingleCharacterStringFromCode(code); + } + return isolate->heap()->empty_string(); } @@ -3293,8 +3383,7 @@ class FixedArrayBuilder { } Handle<JSArray> ToJSArray(Handle<JSArray> target_array) { - Factory* factory = target_array->GetIsolate()->factory(); - factory->SetContent(target_array, array_); + JSArray::SetContent(target_array, array_); target_array->set_length(Smi::FromInt(length_)); return target_array; } @@ -3381,14 +3470,20 @@ class ReplacementStringBuilder { } - Handle<String> ToString() { + MaybeHandle<String> ToString() { + Isolate* isolate = heap_->isolate(); if (array_builder_.length() == 0) { - return heap_->isolate()->factory()->empty_string(); + return isolate->factory()->empty_string(); } Handle<String> joined_string; if (is_ascii_) { - Handle<SeqOneByteString> seq = NewRawOneByteString(character_count_); + Handle<SeqOneByteString> seq; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, seq, + isolate->factory()->NewRawOneByteString(character_count_), + String); + DisallowHeapAllocation no_gc; uint8_t* char_buffer = seq->GetChars(); StringBuilderConcatHelper(*subject_, @@ -3398,7 +3493,12 @@ class ReplacementStringBuilder { joined_string = Handle<String>::cast(seq); } else { // Non-ASCII. - Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_); + Handle<SeqTwoByteString> seq; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, seq, + isolate->factory()->NewRawTwoByteString(character_count_), + String); + DisallowHeapAllocation no_gc; uc16* char_buffer = seq->GetChars(); StringBuilderConcatHelper(*subject_, @@ -3413,22 +3513,14 @@ class ReplacementStringBuilder { void IncrementCharacterCount(int by) { if (character_count_ > String::kMaxLength - by) { - V8::FatalProcessOutOfMemory("String.replace result too large."); + STATIC_ASSERT(String::kMaxLength < kMaxInt); + character_count_ = kMaxInt; + } else { + character_count_ += by; } - character_count_ += by; } private: - Handle<SeqOneByteString> NewRawOneByteString(int length) { - return heap_->isolate()->factory()->NewRawOneByteString(length); - } - - - Handle<SeqTwoByteString> NewRawTwoByteString(int length) { - return heap_->isolate()->factory()->NewRawTwoByteString(length); - } - - void AddElement(Object* element) { ASSERT(element->IsSmi() || element->IsString()); ASSERT(array_builder_.capacity() > array_builder_.length()); @@ -3866,7 +3958,7 @@ void FindStringIndicesDispatch(Isolate* isolate, template<typename ResultSeqString> -MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString( +MUST_USE_RESULT static Object* StringReplaceGlobalAtomRegExpWithString( Isolate* isolate, Handle<String> subject, Handle<JSRegExp> pattern_regexp, @@ -3896,20 +3988,26 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString( static_cast<int64_t>(pattern_len)) * static_cast<int64_t>(matches) + static_cast<int64_t>(subject_len); - if (result_len_64 > INT_MAX) return Failure::OutOfMemoryException(0x11); - int result_len = static_cast<int>(result_len_64); + int result_len; + if (result_len_64 > static_cast<int64_t>(String::kMaxLength)) { + STATIC_ASSERT(String::kMaxLength < kMaxInt); + result_len = kMaxInt; // Provoke exception. + } else { + result_len = static_cast<int>(result_len_64); + } int subject_pos = 0; int result_pos = 0; - Handle<ResultSeqString> result; + MaybeHandle<SeqString> maybe_res; if (ResultSeqString::kHasAsciiEncoding) { - result = Handle<ResultSeqString>::cast( - isolate->factory()->NewRawOneByteString(result_len)); + maybe_res = isolate->factory()->NewRawOneByteString(result_len); } else { - result = Handle<ResultSeqString>::cast( - isolate->factory()->NewRawTwoByteString(result_len)); + maybe_res = isolate->factory()->NewRawTwoByteString(result_len); } + Handle<SeqString> untyped_res; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, untyped_res, maybe_res); + Handle<ResultSeqString> result = Handle<ResultSeqString>::cast(untyped_res); for (int i = 0; i < matches; i++) { // Copy non-matched subject content. @@ -3948,7 +4046,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString( } -MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithString( +MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithString( Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, @@ -3980,11 +4078,11 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithString( } RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); - if (global_cache.HasException()) return Failure::Exception(); + if (global_cache.HasException()) return isolate->heap()->exception(); int32_t* current_match = global_cache.FetchNext(); if (current_match == NULL) { - if (global_cache.HasException()) return Failure::Exception(); + if (global_cache.HasException()) return isolate->heap()->exception(); return *subject; } @@ -4026,7 +4124,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithString( current_match = global_cache.FetchNext(); } while (current_match != NULL); - if (global_cache.HasException()) return Failure::Exception(); + if (global_cache.HasException()) return isolate->heap()->exception(); if (prev < subject_length) { builder.EnsureCapacity(2); @@ -4038,12 +4136,14 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithString( capture_count, global_cache.LastSuccessfulMatch()); - return *(builder.ToString()); + Handle<String> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, builder.ToString()); + return *result; } template <typename ResultSeqString> -MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString( +MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithEmptyString( Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, @@ -4063,11 +4163,11 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString( } RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); - if (global_cache.HasException()) return Failure::Exception(); + if (global_cache.HasException()) return isolate->heap()->exception(); int32_t* current_match = global_cache.FetchNext(); if (current_match == NULL) { - if (global_cache.HasException()) return Failure::Exception(); + if (global_cache.HasException()) return isolate->heap()->exception(); return *subject; } @@ -4082,10 +4182,10 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString( Handle<ResultSeqString> answer; if (ResultSeqString::kHasAsciiEncoding) { answer = Handle<ResultSeqString>::cast( - isolate->factory()->NewRawOneByteString(new_length)); + isolate->factory()->NewRawOneByteString(new_length).ToHandleChecked()); } else { answer = Handle<ResultSeqString>::cast( - isolate->factory()->NewRawTwoByteString(new_length)); + isolate->factory()->NewRawTwoByteString(new_length).ToHandleChecked()); } int prev = 0; @@ -4104,7 +4204,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString( current_match = global_cache.FetchNext(); } while (current_match != NULL); - if (global_cache.HasException()) return Failure::Exception(); + if (global_cache.HasException()) return isolate->heap()->exception(); RegExpImpl::SetLastMatchInfo(last_match_info, subject, @@ -4129,16 +4229,19 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString( if (delta == 0) return *answer; Address end_of_string = answer->address() + string_size; - isolate->heap()->CreateFillerObjectAt(end_of_string, delta); - if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) { - MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta); - } + Heap* heap = isolate->heap(); + // The trimming is performed on a newly allocated object, which is on a + // fresly allocated page or on an already swept page. Hence, the sweeper + // thread can not get confused with the filler creation. No synchronization + // needed. + heap->CreateFillerObjectAt(end_of_string, delta); + heap->AdjustLiveBytes(answer->address(), -delta, Heap::FROM_MUTATOR); return *answer; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceGlobalRegExpWithString) { +RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) { HandleScope scope(isolate); ASSERT(args.length() == 4); @@ -4147,9 +4250,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceGlobalRegExpWithString) { CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3); - ASSERT(regexp->GetFlags().is_global()); + RUNTIME_ASSERT(regexp->GetFlags().is_global()); + RUNTIME_ASSERT(last_match_info->HasFastObjectElements()); - if (!subject->IsFlat()) subject = FlattenGetString(subject); + subject = String::Flatten(subject); if (replacement->length() == 0) { if (subject->HasOnlyOneByteChars()) { @@ -4161,43 +4265,45 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceGlobalRegExpWithString) { } } - if (!replacement->IsFlat()) replacement = FlattenGetString(replacement); + replacement = String::Flatten(replacement); return StringReplaceGlobalRegExpWithString( isolate, subject, regexp, replacement, last_match_info); } -Handle<String> StringReplaceOneCharWithString(Isolate* isolate, - Handle<String> subject, - Handle<String> search, - Handle<String> replace, - bool* found, - int recursion_limit) { - if (recursion_limit == 0) return Handle<String>::null(); +// This may return an empty MaybeHandle if an exception is thrown or +// we abort due to reaching the recursion limit. +MaybeHandle<String> StringReplaceOneCharWithString(Isolate* isolate, + Handle<String> subject, + Handle<String> search, + Handle<String> replace, + bool* found, + int recursion_limit) { + StackLimitCheck stackLimitCheck(isolate); + if (stackLimitCheck.HasOverflowed() || (recursion_limit == 0)) { + return MaybeHandle<String>(); + } + recursion_limit--; if (subject->IsConsString()) { ConsString* cons = ConsString::cast(*subject); Handle<String> first = Handle<String>(cons->first()); Handle<String> second = Handle<String>(cons->second()); - Handle<String> new_first = - StringReplaceOneCharWithString(isolate, - first, - search, - replace, - found, - recursion_limit - 1); + Handle<String> new_first; + if (!StringReplaceOneCharWithString( + isolate, first, search, replace, found, recursion_limit) + .ToHandle(&new_first)) { + return MaybeHandle<String>(); + } if (*found) return isolate->factory()->NewConsString(new_first, second); - if (new_first.is_null()) return new_first; - - Handle<String> new_second = - StringReplaceOneCharWithString(isolate, - second, - search, - replace, - found, - recursion_limit - 1); + + Handle<String> new_second; + if (!StringReplaceOneCharWithString( + isolate, second, search, replace, found, recursion_limit) + .ToHandle(&new_second)) { + return MaybeHandle<String>(); + } if (*found) return isolate->factory()->NewConsString(first, new_second); - if (new_second.is_null()) return new_second; return subject; } else { @@ -4205,7 +4311,11 @@ Handle<String> StringReplaceOneCharWithString(Isolate* isolate, if (index == -1) return subject; *found = true; Handle<String> first = isolate->factory()->NewSubString(subject, 0, index); - Handle<String> cons1 = isolate->factory()->NewConsString(first, replace); + Handle<String> cons1; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, cons1, + isolate->factory()->NewConsString(first, replace), + String); Handle<String> second = isolate->factory()->NewSubString(subject, index + 1, subject->length()); return isolate->factory()->NewConsString(cons1, second); @@ -4213,7 +4323,7 @@ Handle<String> StringReplaceOneCharWithString(Isolate* isolate, } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) { +RUNTIME_FUNCTION(Runtime_StringReplaceOneCharWithString) { HandleScope scope(isolate); ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); @@ -4224,19 +4334,20 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) { // retry with a flattened subject string. const int kRecursionLimit = 0x1000; bool found = false; - Handle<String> result = StringReplaceOneCharWithString(isolate, - subject, - search, - replace, - &found, - kRecursionLimit); - if (!result.is_null()) return *result; - return *StringReplaceOneCharWithString(isolate, - FlattenGetString(subject), - search, - replace, - &found, - kRecursionLimit); + Handle<String> result; + if (StringReplaceOneCharWithString( + isolate, subject, search, replace, &found, kRecursionLimit) + .ToHandle(&result)) { + return *result; + } + if (isolate->has_pending_exception()) return isolate->heap()->exception(); + + subject = String::Flatten(subject); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + StringReplaceOneCharWithString( + isolate, subject, search, replace, &found, kRecursionLimit)); + return *result; } @@ -4256,8 +4367,8 @@ int Runtime::StringMatch(Isolate* isolate, int subject_length = sub->length(); if (start_index + pattern_length > subject_length) return -1; - if (!sub->IsFlat()) FlattenString(sub); - if (!pat->IsFlat()) FlattenString(pat); + sub = String::Flatten(sub); + pat = String::Flatten(pat); DisallowHeapAllocation no_gc; // ensure vectors stay valid // Extract flattened substrings of cons strings before determining asciiness. @@ -4292,20 +4403,19 @@ int Runtime::StringMatch(Isolate* isolate, } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) { +RUNTIME_FUNCTION(Runtime_StringIndexOf) { HandleScope scope(isolate); ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(String, sub, 0); CONVERT_ARG_HANDLE_CHECKED(String, pat, 1); + CONVERT_ARG_HANDLE_CHECKED(Object, index, 2); - Object* index = args[2]; uint32_t start_index; if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length())); - int position = - Runtime::StringMatch(isolate, sub, pat, start_index); + int position = Runtime::StringMatch(isolate, sub, pat, start_index); return Smi::FromInt(position); } @@ -4345,14 +4455,14 @@ static int StringMatchBackwards(Vector<const schar> subject, } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) { +RUNTIME_FUNCTION(Runtime_StringLastIndexOf) { HandleScope scope(isolate); ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(String, sub, 0); CONVERT_ARG_HANDLE_CHECKED(String, pat, 1); + CONVERT_ARG_HANDLE_CHECKED(Object, index, 2); - Object* index = args[2]; uint32_t start_index; if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); @@ -4367,8 +4477,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) { return Smi::FromInt(start_index); } - if (!sub->IsFlat()) FlattenString(sub); - if (!pat->IsFlat()) FlattenString(pat); + sub = String::Flatten(sub); + pat = String::Flatten(pat); int position = -1; DisallowHeapAllocation no_gc; // ensure vectors stay valid @@ -4404,14 +4514,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_StringLocaleCompare) { + HandleScope handle_scope(isolate); ASSERT(args.length() == 2); - CONVERT_ARG_CHECKED(String, str1, 0); - CONVERT_ARG_CHECKED(String, str2, 1); + CONVERT_ARG_HANDLE_CHECKED(String, str1, 0); + CONVERT_ARG_HANDLE_CHECKED(String, str2, 1); - if (str1 == str2) return Smi::FromInt(0); // Equal. + if (str1.is_identical_to(str2)) return Smi::FromInt(0); // Equal. int str1_length = str1->length(); int str2_length = str2->length(); @@ -4431,32 +4541,28 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) { int d = str1->Get(0) - str2->Get(0); if (d != 0) return Smi::FromInt(d); - str1->TryFlatten(); - str2->TryFlatten(); + str1 = String::Flatten(str1); + str2 = String::Flatten(str2); - ConsStringIteratorOp* op1 = - isolate->runtime_state()->string_locale_compare_it1(); - ConsStringIteratorOp* op2 = - isolate->runtime_state()->string_locale_compare_it2(); - // TODO(dcarney) Can do array compares here more efficiently. - StringCharacterStream stream1(str1, op1); - StringCharacterStream stream2(str2, op2); + DisallowHeapAllocation no_gc; + String::FlatContent flat1 = str1->GetFlatContent(); + String::FlatContent flat2 = str2->GetFlatContent(); for (int i = 0; i < end; i++) { - uint16_t char1 = stream1.GetNext(); - uint16_t char2 = stream2.GetNext(); - if (char1 != char2) return Smi::FromInt(char1 - char2); + if (flat1.Get(i) != flat2.Get(i)) { + return Smi::FromInt(flat1.Get(i) - flat2.Get(i)); + } } return Smi::FromInt(str1_length - str2_length); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_SubString) { + HandleScope scope(isolate); ASSERT(args.length() == 3); - CONVERT_ARG_CHECKED(String, value, 0); + CONVERT_ARG_HANDLE_CHECKED(String, string, 0); int start, end; // We have a fast integer-only case here to avoid a conversion to double in // the common case where from and to are Smis. @@ -4473,22 +4579,25 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) { } RUNTIME_ASSERT(end >= start); RUNTIME_ASSERT(start >= 0); - RUNTIME_ASSERT(end <= value->length()); + RUNTIME_ASSERT(end <= string->length()); isolate->counters()->sub_string_runtime()->Increment(); - return value->SubString(start, end); + + return *isolate->factory()->NewSubString(string, start, end); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) { +RUNTIME_FUNCTION(Runtime_StringMatch) { HandleScope handles(isolate); - ASSERT_EQ(3, args.length()); + ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2); + RUNTIME_ASSERT(regexp_info->HasFastObjectElements()); + RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); - if (global_cache.HasException()) return Failure::Exception(); + if (global_cache.HasException()) return isolate->heap()->exception(); int capture_count = regexp->CaptureCount(); @@ -4502,7 +4611,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) { offsets.Add(match[1], zone_scope.zone()); // end } - if (global_cache.HasException()) return Failure::Exception(); + if (global_cache.HasException()) return isolate->heap()->exception(); if (offsets.length() == 0) { // Not a single match. @@ -4536,7 +4645,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) { // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain // separate last match info. See comment on that function. template<bool has_capture> -static MaybeObject* SearchRegExpMultiple( +static Object* SearchRegExpMultiple( Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, @@ -4560,7 +4669,7 @@ static MaybeObject* SearchRegExpMultiple( Handle<FixedArray> cached_fixed_array = Handle<FixedArray>(FixedArray::cast(*cached_answer)); // The cache FixedArray is a COW-array and can therefore be reused. - isolate->factory()->SetContent(result_array, cached_fixed_array); + JSArray::SetContent(result_array, cached_fixed_array); // The actual length of the result array is stored in the last element of // the backing store (the backing FixedArray may have a larger capacity). Object* cached_fixed_array_last_element = @@ -4574,14 +4683,13 @@ static MaybeObject* SearchRegExpMultiple( } RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); - if (global_cache.HasException()) return Failure::Exception(); + if (global_cache.HasException()) return isolate->heap()->exception(); - Handle<FixedArray> result_elements; - if (result_array->HasFastObjectElements()) { - result_elements = - Handle<FixedArray>(FixedArray::cast(result_array->elements())); - } - if (result_elements.is_null() || result_elements->length() < 16) { + // Ensured in Runtime_RegExpExecMultiple. + ASSERT(result_array->HasFastObjectElements()); + Handle<FixedArray> result_elements( + FixedArray::cast(result_array->elements())); + if (result_elements->length() < 16) { result_elements = isolate->factory()->NewFixedArrayWithHoles(16); } @@ -4650,7 +4758,7 @@ static MaybeObject* SearchRegExpMultiple( } } - if (global_cache.HasException()) return Failure::Exception(); + if (global_cache.HasException()) return isolate->heap()->exception(); if (match_start >= 0) { // Finished matching, with at least one match. @@ -4671,10 +4779,10 @@ static MaybeObject* SearchRegExpMultiple( fixed_array->set(fixed_array->length() - 1, Smi::FromInt(builder.length())); // Cache the result and turn the FixedArray into a COW array. - RegExpResultsCache::Enter(isolate->heap(), - *subject, - regexp->data(), - *fixed_array, + RegExpResultsCache::Enter(isolate, + subject, + handle(regexp->data(), isolate), + fixed_array, RegExpResultsCache::REGEXP_MULTIPLE_INDICES); } return *builder.ToJSArray(result_array); @@ -4687,17 +4795,19 @@ static MaybeObject* SearchRegExpMultiple( // This is only called for StringReplaceGlobalRegExpWithFunction. This sets // lastMatchInfoOverride to maintain the last match info, so we don't need to // set any other last match array info. -RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) { +RUNTIME_FUNCTION(Runtime_RegExpExecMultiple) { HandleScope handles(isolate); ASSERT(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); - if (!subject->IsFlat()) FlattenString(subject); CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2); CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3); + RUNTIME_ASSERT(last_match_info->HasFastObjectElements()); + RUNTIME_ASSERT(result_array->HasFastObjectElements()); - ASSERT(regexp->GetFlags().is_global()); + subject = String::Flatten(subject); + RUNTIME_ASSERT(regexp->GetFlags().is_global()); if (regexp->CaptureCount() == 0) { return SearchRegExpMultiple<false>( @@ -4709,8 +4819,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberToRadixString) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_SMI_ARG_CHECKED(radix, 1); RUNTIME_ASSERT(2 <= radix && radix <= 36); @@ -4721,7 +4831,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) { if (value >= 0 && value < radix) { // Character array used for conversion. static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz"; - return isolate->heap()-> + return *isolate->factory()-> LookupSingleCharacterStringFromCode(kCharTable[value]); } } @@ -4729,80 +4839,76 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) { // Slow case. CONVERT_DOUBLE_ARG_CHECKED(value, 0); if (std::isnan(value)) { - return *isolate->factory()->nan_string(); + return isolate->heap()->nan_string(); } if (std::isinf(value)) { if (value < 0) { - return *isolate->factory()->minus_infinity_string(); + return isolate->heap()->minus_infinity_string(); } - return *isolate->factory()->infinity_string(); + return isolate->heap()->infinity_string(); } char* str = DoubleToRadixCString(value, radix); - MaybeObject* result = - isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); + Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); DeleteArray(str); - return result; + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberToFixed) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_DOUBLE_ARG_CHECKED(value, 0); CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); int f = FastD2IChecked(f_number); - RUNTIME_ASSERT(f >= 0); + // See DoubleToFixedCString for these constants: + RUNTIME_ASSERT(f >= 0 && f <= 20); + RUNTIME_ASSERT(!Double(value).IsSpecial()); char* str = DoubleToFixedCString(value, f); - MaybeObject* res = - isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); + Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); DeleteArray(str); - return res; + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberToExponential) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_DOUBLE_ARG_CHECKED(value, 0); CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); int f = FastD2IChecked(f_number); RUNTIME_ASSERT(f >= -1 && f <= 20); + RUNTIME_ASSERT(!Double(value).IsSpecial()); char* str = DoubleToExponentialCString(value, f); - MaybeObject* res = - isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); + Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); DeleteArray(str); - return res; + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberToPrecision) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_DOUBLE_ARG_CHECKED(value, 0); CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); int f = FastD2IChecked(f_number); RUNTIME_ASSERT(f >= 1 && f <= 21); + RUNTIME_ASSERT(!Double(value).IsSpecial()); char* str = DoubleToPrecisionCString(value, f); - MaybeObject* res = - isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); + Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); DeleteArray(str); - return res; + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsValidSmi) { - HandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_IsValidSmi) { + SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]); - if (Smi::IsValid(number)) { - return isolate->heap()->true_value(); - } else { - return isolate->heap()->false_value(); - } + return isolate->heap()->ToBoolean(Smi::IsValid(number)); } @@ -4810,30 +4916,21 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_IsValidSmi) { // string->Get(index). static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { if (index < static_cast<uint32_t>(string->length())) { - string->TryFlatten(); - return LookupSingleCharacterStringFromCode( - string->GetIsolate(), - string->Get(index)); + Factory* factory = string->GetIsolate()->factory(); + return factory->LookupSingleCharacterStringFromCode( + String::Flatten(string)->Get(index)); } return Execution::CharAt(string, index); } -MaybeObject* Runtime::GetElementOrCharAtOrFail(Isolate* isolate, - Handle<Object> object, - uint32_t index) { - CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate, - GetElementOrCharAt(isolate, object, index)); -} - - -MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate, - Handle<Object> object, - uint32_t index) { +MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate, + Handle<Object> object, + uint32_t index) { // Handle [] indexing on Strings if (object->IsString()) { Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); - if (!result->IsUndefined()) return *result; + if (!result->IsUndefined()) return result; } // Handle [] indexing on String objects @@ -4841,67 +4938,57 @@ MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate, Handle<JSValue> js_value = Handle<JSValue>::cast(object); Handle<Object> result = GetCharAt(Handle<String>(String::cast(js_value->value())), index); - if (!result->IsUndefined()) return *result; + if (!result->IsUndefined()) return result; } + Handle<Object> result; if (object->IsString() || object->IsNumber() || object->IsBoolean()) { - return object->GetPrototype(isolate)->GetElement(isolate, index); + Handle<Object> proto(object->GetPrototype(isolate), isolate); + return Object::GetElement(isolate, proto, index); + } else { + return Object::GetElement(isolate, object, index); } - - return object->GetElement(isolate, index); } -static Handle<Name> ToName(Isolate* isolate, Handle<Object> key) { +MUST_USE_RESULT +static MaybeHandle<Name> ToName(Isolate* isolate, Handle<Object> key) { if (key->IsName()) { return Handle<Name>::cast(key); } else { - bool has_pending_exception = false; - Handle<Object> converted = - Execution::ToString(isolate, key, &has_pending_exception); - if (has_pending_exception) return Handle<Name>(); + Handle<Object> converted; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, converted, Execution::ToString(isolate, key), Name); return Handle<Name>::cast(converted); } } -MaybeObject* Runtime::HasObjectProperty(Isolate* isolate, - Handle<JSReceiver> object, - Handle<Object> key) { - HandleScope scope(isolate); - +MaybeHandle<Object> Runtime::HasObjectProperty(Isolate* isolate, + Handle<JSReceiver> object, + Handle<Object> key) { // Check if the given key is an array index. uint32_t index; if (key->ToArrayIndex(&index)) { - return isolate->heap()->ToBoolean(JSReceiver::HasElement(object, index)); + return isolate->factory()->ToBoolean(JSReceiver::HasElement(object, index)); } // Convert the key to a name - possibly by calling back into JavaScript. - Handle<Name> name = ToName(isolate, key); - RETURN_IF_EMPTY_HANDLE(isolate, name); - - return isolate->heap()->ToBoolean(JSReceiver::HasProperty(object, name)); -} + Handle<Name> name; + ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object); -MaybeObject* Runtime::GetObjectPropertyOrFail( - Isolate* isolate, - Handle<Object> object, - Handle<Object> key) { - CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate, - GetObjectProperty(isolate, object, key)); + return isolate->factory()->ToBoolean(JSReceiver::HasProperty(object, name)); } -MaybeObject* Runtime::GetObjectProperty(Isolate* isolate, - Handle<Object> object, - Handle<Object> key) { - HandleScope scope(isolate); +MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, + Handle<Object> object, + Handle<Object> key) { if (object->IsUndefined() || object->IsNull()) { Handle<Object> args[2] = { key, object }; - Handle<Object> error = + return isolate->Throw<Object>( isolate->factory()->NewTypeError("non_object_property_load", - HandleVector(args, 2)); - return isolate->Throw(*error); + HandleVector(args, 2))); } // Check if the given key is an array index. @@ -4911,60 +4998,68 @@ MaybeObject* Runtime::GetObjectProperty(Isolate* isolate, } // Convert the key to a name - possibly by calling back into JavaScript. - Handle<Name> name = ToName(isolate, key); - RETURN_IF_EMPTY_HANDLE(isolate, name); + Handle<Name> name; + ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object); // Check if the name is trivially convertible to an index and get // the element if so. if (name->AsArrayIndex(&index)) { return GetElementOrCharAt(isolate, object, index); } else { - return object->GetProperty(*name); + return Object::GetProperty(object, name); } } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_GetProperty) { + HandleScope scope(isolate); ASSERT(args.length() == 2); - Handle<Object> object = args.at<Object>(0); - Handle<Object> key = args.at<Object>(1); - - return Runtime::GetObjectProperty(isolate, object, key); + CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); + CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + Runtime::GetObjectProperty(isolate, object, key)); + return *result; } // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric. -RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { + HandleScope scope(isolate); ASSERT(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); + CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); + // Fast cases for getting named properties of the receiver JSObject // itself. // - // The global proxy objects has to be excluded since LocalLookup on + // The global proxy objects has to be excluded since LookupOwn on // the global proxy object can return a valid result even though the // global proxy object never has properties. This is the case // because the global proxy object forwards everything to its hidden - // prototype including local lookups. + // prototype including own lookups. // // Additionally, we need to make sure that we do not cache results // for objects that require access checks. - if (args[0]->IsJSObject()) { - if (!args[0]->IsJSGlobalProxy() && - !args[0]->IsAccessCheckNeeded() && - args[1]->IsName()) { - JSObject* receiver = JSObject::cast(args[0]); - Name* key = Name::cast(args[1]); + if (receiver_obj->IsJSObject()) { + if (!receiver_obj->IsJSGlobalProxy() && + !receiver_obj->IsAccessCheckNeeded() && + key_obj->IsName()) { + DisallowHeapAllocation no_allocation; + Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj); + Handle<Name> key = Handle<Name>::cast(key_obj); if (receiver->HasFastProperties()) { // Attempt to use lookup cache. - Map* receiver_map = receiver->map(); + Handle<Map> receiver_map(receiver->map(), isolate); KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache(); - int offset = keyed_lookup_cache->Lookup(receiver_map, key); - if (offset != -1) { + int index = keyed_lookup_cache->Lookup(receiver_map, key); + if (index != -1) { // Doubles are not cached, so raw read the value. - Object* value = receiver->RawFastPropertyAt(offset); + Object* value = receiver->RawFastPropertyAt( + FieldIndex::ForKeyedLookupCacheIndex(*receiver_map, index)); return value->IsTheHole() ? isolate->heap()->undefined_value() : value; @@ -4972,16 +5067,18 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) { // Lookup cache miss. Perform lookup and update the cache if // appropriate. LookupResult result(isolate); - receiver->LocalLookup(key, &result); + receiver->LookupOwn(key, &result); if (result.IsField()) { - int offset = result.GetFieldIndex().field_index(); + FieldIndex field_index = result.GetFieldIndex(); // Do not track double fields in the keyed lookup cache. Reading // double values requires boxing. - if (!FLAG_track_double_fields || - !result.representation().IsDouble()) { - keyed_lookup_cache->Update(receiver_map, key, offset); + if (!result.representation().IsDouble()) { + keyed_lookup_cache->Update(receiver_map, key, + field_index.GetKeyedLookupCacheIndex()); } - return receiver->FastPropertyAt(result.representation(), offset); + AllowHeapAllocation allow_allocation; + return *JSObject::FastPropertyAt(receiver, result.representation(), + field_index); } } else { // Attempt dictionary lookup. @@ -4996,48 +5093,46 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) { // If value is the hole do the general lookup. } } - } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) { + } else if (FLAG_smi_only_arrays && key_obj->IsSmi()) { // JSObject without a name key. If the key is a Smi, check for a // definite out-of-bounds access to elements, which is a strong indicator // that subsequent accesses will also call the runtime. Proactively // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of // doubles for those future calls in the case that the elements would // become FAST_DOUBLE_ELEMENTS. - Handle<JSObject> js_object(args.at<JSObject>(0)); + Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj); ElementsKind elements_kind = js_object->GetElementsKind(); if (IsFastDoubleElementsKind(elements_kind)) { - FixedArrayBase* elements = js_object->elements(); - if (args.at<Smi>(1)->value() >= elements->length()) { + Handle<Smi> key = Handle<Smi>::cast(key_obj); + if (key->value() >= js_object->elements()->length()) { if (IsFastHoleyElementsKind(elements_kind)) { elements_kind = FAST_HOLEY_ELEMENTS; } else { elements_kind = FAST_ELEMENTS; } - MaybeObject* maybe_object = TransitionElements(js_object, - elements_kind, - isolate); - if (maybe_object->IsFailure()) return maybe_object; + RETURN_FAILURE_ON_EXCEPTION( + isolate, TransitionElements(js_object, elements_kind, isolate)); } } else { ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) || !IsFastElementsKind(elements_kind)); } } - } else if (args[0]->IsString() && args[1]->IsSmi()) { + } else if (receiver_obj->IsString() && key_obj->IsSmi()) { // Fast case for string indexing using [] with a smi index. - HandleScope scope(isolate); - Handle<String> str = args.at<String>(0); + Handle<String> str = Handle<String>::cast(receiver_obj); int index = args.smi_at(1); if (index >= 0 && index < str->length()) { - Handle<Object> result = GetCharAt(str, index); - return *result; + return *GetCharAt(str, index); } } // Fall back to GetObjectProperty. - return Runtime::GetObjectProperty(isolate, - args.at<Object>(0), - args.at<Object>(1)); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + Runtime::GetObjectProperty(isolate, receiver_obj, key_obj)); + return *result; } @@ -5052,7 +5147,7 @@ static bool IsValidAccessor(Handle<Object> obj) { // Steps 9c & 12 - replace an existing data property with an accessor property. // Step 12 - update an existing accessor property with an accessor or generic // descriptor. -RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) { +RUNTIME_FUNCTION(Runtime_DefineOrRedefineAccessorProperty) { HandleScope scope(isolate); ASSERT(args.length() == 5); CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); @@ -5067,8 +5162,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) { PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); bool fast = obj->HasFastProperties(); + // DefineAccessor checks access rights. JSObject::DefineAccessor(obj, name, getter, setter, attr); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); if (fast) JSObject::TransformToFastProperties(obj, 0); return isolate->heap()->undefined_value(); } @@ -5080,7 +5176,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) { // Steps 9b & 12 - replace an existing accessor property with a data property. // Step 12 - update an existing data property with a data or generic // descriptor. -RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) { +RUNTIME_FUNCTION(Runtime_DefineOrRedefineDataProperty) { HandleScope scope(isolate); ASSERT(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0); @@ -5090,35 +5186,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) { RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); - LookupResult lookup(isolate); - js_object->LocalLookupRealNamedProperty(*name, &lookup); - - // Special case for callback properties. - if (lookup.IsPropertyCallbacks()) { - Handle<Object> callback(lookup.GetCallbackObject(), isolate); - // To be compatible with Safari we do not change the value on API objects - // in Object.defineProperty(). Firefox disagrees here, and actually changes - // the value. - if (callback->IsAccessorInfo()) { - return isolate->heap()->undefined_value(); - } - // Avoid redefining foreign callback as data property, just use the stored - // setter to update the value instead. - // TODO(mstarzinger): So far this only works if property attributes don't - // change, this should be fixed once we cleanup the underlying code. - if (callback->IsForeign() && lookup.GetAttributes() == attr) { - Handle<Object> result_object = - JSObject::SetPropertyWithCallback(js_object, - callback, - name, - obj_value, - handle(lookup.holder()), - kStrictMode); - RETURN_IF_EMPTY_HANDLE(isolate, result_object); - return *result_object; - } + // Check access rights if needed. + if (js_object->IsAccessCheckNeeded() && + !isolate->MayNamedAccess(js_object, name, v8::ACCESS_SET)) { + return isolate->heap()->undefined_value(); } + LookupResult lookup(isolate); + js_object->LookupOwnRealNamedProperty(name, &lookup); + // Take special care when attributes are different and there is already // a property. For simplicity we normalize the property which enables us // to not worry about changing the instance_descriptor and creating a new @@ -5133,60 +5209,54 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) { // we don't have to check for null. js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype())); } - JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0); + + if (attr != lookup.GetAttributes() || + (lookup.IsPropertyCallbacks() && + !lookup.GetCallbackObject()->IsAccessorInfo())) { + JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0); + } + // Use IgnoreAttributes version since a readonly property may be // overridden and SetProperty does not allow this. - Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes( - js_object, name, obj_value, attr); - RETURN_IF_EMPTY_HANDLE(isolate, result); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + JSObject::SetOwnPropertyIgnoreAttributes( + js_object, name, obj_value, attr, + Object::OPTIMAL_REPRESENTATION, + ALLOW_AS_CONSTANT, + JSReceiver::PERFORM_EXTENSIBILITY_CHECK, + JSReceiver::MAY_BE_STORE_FROM_KEYED, + JSObject::DONT_FORCE_FIELD)); return *result; } - Handle<Object> result = Runtime::ForceSetObjectProperty(isolate, js_object, - name, - obj_value, - attr); - RETURN_IF_EMPTY_HANDLE(isolate, result); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + Runtime::ForceSetObjectProperty( + js_object, name, obj_value, attr, + JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED)); return *result; } // Return property without being observable by accessors or interceptors. -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDataProperty) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_GetDataProperty) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); - LookupResult lookup(isolate); - object->LookupRealNamedProperty(*key, &lookup); - if (!lookup.IsFound()) return isolate->heap()->undefined_value(); - switch (lookup.type()) { - case NORMAL: - return lookup.holder()->GetNormalizedProperty(&lookup); - case FIELD: - return lookup.holder()->FastPropertyAt( - lookup.representation(), - lookup.GetFieldIndex().field_index()); - case CONSTANT: - return lookup.GetConstant(); - case CALLBACKS: - case HANDLER: - case INTERCEPTOR: - case TRANSITION: - return isolate->heap()->undefined_value(); - case NONEXISTENT: - UNREACHABLE(); - } - return isolate->heap()->undefined_value(); + return *JSObject::GetDataProperty(object, key); } -Handle<Object> Runtime::SetObjectProperty(Isolate* isolate, - Handle<Object> object, - Handle<Object> key, - Handle<Object> value, - PropertyAttributes attr, - StrictModeFlag strict_mode) { +MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate, + Handle<Object> object, + Handle<Object> key, + Handle<Object> value, + PropertyAttributes attr, + StrictMode strict_mode) { SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY; if (object->IsUndefined() || object->IsNull()) { @@ -5194,15 +5264,17 @@ Handle<Object> Runtime::SetObjectProperty(Isolate* isolate, Handle<Object> error = isolate->factory()->NewTypeError("non_object_property_store", HandleVector(args, 2)); - isolate->Throw(*error); - return Handle<Object>(); + return isolate->Throw<Object>(error); } if (object->IsJSProxy()) { - bool has_pending_exception = false; - Handle<Object> name_object = key->IsSymbol() - ? key : Execution::ToString(isolate, key, &has_pending_exception); - if (has_pending_exception) return Handle<Object>(); // exception + Handle<Object> name_object; + if (key->IsSymbol()) { + name_object = key; + } else { + ASSIGN_RETURN_ON_EXCEPTION( + isolate, name_object, Execution::ToString(isolate, key), Object); + } Handle<Name> name = Handle<Name>::cast(name_object); return JSReceiver::SetProperty(Handle<JSProxy>::cast(object), name, value, attr, @@ -5228,21 +5300,19 @@ Handle<Object> Runtime::SetObjectProperty(Isolate* isolate, return value; } - js_object->ValidateElements(); - if (js_object->HasExternalArrayElements()) { + JSObject::ValidateElements(js_object); + if (js_object->HasExternalArrayElements() || + js_object->HasFixedTypedArrayElements()) { if (!value->IsNumber() && !value->IsUndefined()) { - bool has_exception; - Handle<Object> number = - Execution::ToNumber(isolate, value, &has_exception); - if (has_exception) return Handle<Object>(); // exception - value = number; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, value, Execution::ToNumber(isolate, value), Object); } } - Handle<Object> result = JSObject::SetElement(js_object, index, value, attr, - strict_mode, - true, - set_mode); - js_object->ValidateElements(); + + MaybeHandle<Object> result = JSObject::SetElement( + js_object, index, value, attr, strict_mode, true, set_mode); + JSObject::ValidateElements(js_object); + return result.is_null() ? result : value; } @@ -5251,44 +5321,40 @@ Handle<Object> Runtime::SetObjectProperty(Isolate* isolate, if (name->AsArrayIndex(&index)) { if (js_object->HasExternalArrayElements()) { if (!value->IsNumber() && !value->IsUndefined()) { - bool has_exception; - Handle<Object> number = - Execution::ToNumber(isolate, value, &has_exception); - if (has_exception) return Handle<Object>(); // exception - value = number; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, value, Execution::ToNumber(isolate, value), Object); } } - return JSObject::SetElement(js_object, index, value, attr, strict_mode, - true, - set_mode); + return JSObject::SetElement(js_object, index, value, attr, + strict_mode, true, set_mode); } else { - if (name->IsString()) Handle<String>::cast(name)->TryFlatten(); + if (name->IsString()) name = String::Flatten(Handle<String>::cast(name)); return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode); } } // Call-back into JavaScript to convert the key to a string. - bool has_pending_exception = false; - Handle<Object> converted = - Execution::ToString(isolate, key, &has_pending_exception); - if (has_pending_exception) return Handle<Object>(); // exception + Handle<Object> converted; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, converted, Execution::ToString(isolate, key), Object); Handle<String> name = Handle<String>::cast(converted); if (name->AsArrayIndex(&index)) { - return JSObject::SetElement(js_object, index, value, attr, strict_mode, - true, - set_mode); + return JSObject::SetElement(js_object, index, value, attr, + strict_mode, true, set_mode); } else { return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode); } } -Handle<Object> Runtime::ForceSetObjectProperty(Isolate* isolate, - Handle<JSObject> js_object, - Handle<Object> key, - Handle<Object> value, - PropertyAttributes attr) { +MaybeHandle<Object> Runtime::ForceSetObjectProperty( + Handle<JSObject> js_object, + Handle<Object> key, + Handle<Object> value, + PropertyAttributes attr, + JSReceiver::StoreFromKeyed store_from_keyed) { + Isolate* isolate = js_object->GetIsolate(); // Check if the given key is an array index. uint32_t index; if (key->ToArrayIndex(&index)) { @@ -5303,48 +5369,46 @@ Handle<Object> Runtime::ForceSetObjectProperty(Isolate* isolate, return value; } - return JSObject::SetElement(js_object, index, value, attr, kNonStrictMode, - false, - DEFINE_PROPERTY); + return JSObject::SetElement(js_object, index, value, attr, + SLOPPY, false, DEFINE_PROPERTY); } if (key->IsName()) { Handle<Name> name = Handle<Name>::cast(key); if (name->AsArrayIndex(&index)) { - return JSObject::SetElement(js_object, index, value, attr, kNonStrictMode, - false, - DEFINE_PROPERTY); + return JSObject::SetElement(js_object, index, value, attr, + SLOPPY, false, DEFINE_PROPERTY); } else { - if (name->IsString()) Handle<String>::cast(name)->TryFlatten(); - return JSObject::SetLocalPropertyIgnoreAttributes(js_object, name, - value, attr); + if (name->IsString()) name = String::Flatten(Handle<String>::cast(name)); + return JSObject::SetOwnPropertyIgnoreAttributes( + js_object, name, value, attr, Object::OPTIMAL_REPRESENTATION, + ALLOW_AS_CONSTANT, JSReceiver::PERFORM_EXTENSIBILITY_CHECK, + store_from_keyed); } } // Call-back into JavaScript to convert the key to a string. - bool has_pending_exception = false; - Handle<Object> converted = - Execution::ToString(isolate, key, &has_pending_exception); - if (has_pending_exception) return Handle<Object>(); // exception + Handle<Object> converted; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, converted, Execution::ToString(isolate, key), Object); Handle<String> name = Handle<String>::cast(converted); if (name->AsArrayIndex(&index)) { - return JSObject::SetElement(js_object, index, value, attr, kNonStrictMode, - false, - DEFINE_PROPERTY); + return JSObject::SetElement(js_object, index, value, attr, + SLOPPY, false, DEFINE_PROPERTY); } else { - return JSObject::SetLocalPropertyIgnoreAttributes(js_object, name, value, - attr); + return JSObject::SetOwnPropertyIgnoreAttributes( + js_object, name, value, attr, Object::OPTIMAL_REPRESENTATION, + ALLOW_AS_CONSTANT, JSReceiver::PERFORM_EXTENSIBILITY_CHECK, + store_from_keyed); } } -MaybeObject* Runtime::DeleteObjectProperty(Isolate* isolate, - Handle<JSReceiver> receiver, - Handle<Object> key, - JSReceiver::DeleteMode mode) { - HandleScope scope(isolate); - +MaybeHandle<Object> Runtime::DeleteObjectProperty(Isolate* isolate, + Handle<JSReceiver> receiver, + Handle<Object> key, + JSReceiver::DeleteMode mode) { // Check if the given key is an array index. uint32_t index; if (key->ToArrayIndex(&index)) { @@ -5355,12 +5419,10 @@ MaybeObject* Runtime::DeleteObjectProperty(Isolate* isolate, // underlying string does nothing with the deletion, we can ignore // such deletions. if (receiver->IsStringObjectWithCharacterAt(index)) { - return isolate->heap()->true_value(); + return isolate->factory()->true_value(); } - Handle<Object> result = JSReceiver::DeleteElement(receiver, index, mode); - RETURN_IF_EMPTY_HANDLE(isolate, result); - return *result; + return JSReceiver::DeleteElement(receiver, index, mode); } Handle<Name> name; @@ -5368,21 +5430,30 @@ MaybeObject* Runtime::DeleteObjectProperty(Isolate* isolate, name = Handle<Name>::cast(key); } else { // Call-back into JavaScript to convert the key to a string. - bool has_pending_exception = false; - Handle<Object> converted = Execution::ToString( - isolate, key, &has_pending_exception); - if (has_pending_exception) return Failure::Exception(); + Handle<Object> converted; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, converted, Execution::ToString(isolate, key), Object); name = Handle<String>::cast(converted); } - if (name->IsString()) Handle<String>::cast(name)->TryFlatten(); - Handle<Object> result = JSReceiver::DeleteProperty(receiver, name, mode); - RETURN_IF_EMPTY_HANDLE(isolate, result); - return *result; + if (name->IsString()) name = String::Flatten(Handle<String>::cast(name)); + return JSReceiver::DeleteProperty(receiver, name, mode); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) { +RUNTIME_FUNCTION(Runtime_SetHiddenProperty) { + HandleScope scope(isolate); + RUNTIME_ASSERT(args.length() == 3); + + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); + CONVERT_ARG_HANDLE_CHECKED(String, key, 1); + CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); + RUNTIME_ASSERT(key->IsUniqueName()); + return *JSObject::SetHiddenProperty(object, key, value); +} + + +RUNTIME_FUNCTION(Runtime_SetProperty) { HandleScope scope(isolate); RUNTIME_ASSERT(args.length() == 4 || args.length() == 5); @@ -5396,22 +5467,22 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) { PropertyAttributes attributes = static_cast<PropertyAttributes>(unchecked_attributes); - StrictModeFlag strict_mode = kNonStrictMode; + StrictMode strict_mode = SLOPPY; if (args.length() == 5) { - CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4); - strict_mode = strict_mode_flag; + CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_arg, 4); + strict_mode = strict_mode_arg; } - Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key, - value, - attributes, - strict_mode); - RETURN_IF_EMPTY_HANDLE(isolate, result); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + Runtime::SetObjectProperty( + isolate, object, key, value, attributes, strict_mode)); return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsKind) { +RUNTIME_FUNCTION(Runtime_TransitionElementsKind) { HandleScope scope(isolate); RUNTIME_ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); @@ -5424,7 +5495,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsKind) { // Set the native flag on the function. // This is used to decide if we should transform null and undefined // into the global object when doing call and apply. -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) { +RUNTIME_FUNCTION(Runtime_SetNativeFlag) { SealHandleScope shs(isolate); RUNTIME_ASSERT(args.length() == 1); @@ -5438,11 +5509,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInlineBuiltinFlag) { +RUNTIME_FUNCTION(Runtime_SetInlineBuiltinFlag) { SealHandleScope shs(isolate); RUNTIME_ASSERT(args.length() == 1); - - Handle<Object> object = args.at<Object>(0); + CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); if (object->IsJSFunction()) { JSFunction* func = JSFunction::cast(*object); @@ -5452,12 +5522,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInlineBuiltinFlag) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) { +RUNTIME_FUNCTION(Runtime_StoreArrayLiteralElement) { HandleScope scope(isolate); RUNTIME_ASSERT(args.length() == 5); CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); CONVERT_SMI_ARG_CHECKED(store_index, 1); - Handle<Object> value = args.at<Object>(2); + CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3); CONVERT_SMI_ARG_CHECKED(literal_index, 4); @@ -5491,16 +5561,17 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) { HeapNumber* number = HeapNumber::cast(*value); double_array->set(store_index, number->Number()); } else { - ASSERT(IsFastSmiElementsKind(elements_kind) || - IsFastDoubleElementsKind(elements_kind)); - ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind) - ? FAST_HOLEY_ELEMENTS - : FAST_ELEMENTS; - JSObject::TransitionElementsKind(object, transitioned_kind); - if (IsMoreGeneralElementsKindTransition( - boilerplate_object->GetElementsKind(), - transitioned_kind)) { - JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind); + if (!IsFastObjectElementsKind(elements_kind)) { + ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind) + ? FAST_HOLEY_ELEMENTS + : FAST_ELEMENTS; + JSObject::TransitionElementsKind(object, transitioned_kind); + ElementsKind boilerplate_elements_kind = + boilerplate_object->GetElementsKind(); + if (IsMoreGeneralElementsKindTransition(boilerplate_elements_kind, + transitioned_kind)) { + JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind); + } } FixedArray* object_array = FixedArray::cast(object->elements()); object_array->set(store_index, *value); @@ -5511,29 +5582,22 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) { // Check whether debugger and is about to step into the callback that is passed // to a built-in function such as Array.forEach. -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugCallbackSupportsStepping) { - SealHandleScope shs(isolate); -#ifdef ENABLE_DEBUGGER_SUPPORT - if (!isolate->IsDebuggerActive() || !isolate->debug()->StepInActive()) { +RUNTIME_FUNCTION(Runtime_DebugCallbackSupportsStepping) { + ASSERT(args.length() == 1); + if (!isolate->debug()->is_active() || !isolate->debug()->StepInActive()) { return isolate->heap()->false_value(); } CONVERT_ARG_CHECKED(Object, callback, 0); // We do not step into the callback if it's a builtin or not even a function. - if (!callback->IsJSFunction() || JSFunction::cast(callback)->IsBuiltin()) { - return isolate->heap()->false_value(); - } - return isolate->heap()->true_value(); -#else - return isolate->heap()->false_value(); -#endif // ENABLE_DEBUGGER_SUPPORT + return isolate->heap()->ToBoolean( + callback->IsJSFunction() && !JSFunction::cast(callback)->IsBuiltin()); } // Set one shot breakpoints for the callback function that is passed to a // built-in function such as Array.forEach to enable stepping into the callback. -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrepareStepInIfStepping) { - SealHandleScope shs(isolate); -#ifdef ENABLE_DEBUGGER_SUPPORT +RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) { + ASSERT(args.length() == 1); Debug* debug = isolate->debug(); if (!debug->IsStepping()) return isolate->heap()->undefined_value(); CONVERT_ARG_HANDLE_CHECKED(JSFunction, callback, 0); @@ -5543,14 +5607,33 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrepareStepInIfStepping) { // again, we need to clear the step out at this point. debug->ClearStepOut(); debug->FloodWithOneShot(callback); -#endif // ENABLE_DEBUGGER_SUPPORT return isolate->heap()->undefined_value(); } -// Set a local property, even if it is READ_ONLY. If the property does not +// The argument is a closure that is kept until the epilogue is called. +// On exception, the closure is called, which returns the promise if the +// exception is considered uncaught, or undefined otherwise. +RUNTIME_FUNCTION(Runtime_DebugPromiseHandlePrologue) { + ASSERT(args.length() == 1); + HandleScope scope(isolate); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, promise_getter, 0); + isolate->debug()->PromiseHandlePrologue(promise_getter); + return isolate->heap()->undefined_value(); +} + + +RUNTIME_FUNCTION(Runtime_DebugPromiseHandleEpilogue) { + ASSERT(args.length() == 0); + SealHandleScope shs(isolate); + isolate->debug()->PromiseHandleEpilogue(); + return isolate->heap()->undefined_value(); +} + + +// Set an own property, even if it is READ_ONLY. If the property does not // exist, it will be added with attributes NONE. -RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) { +RUNTIME_FUNCTION(Runtime_IgnoreAttributesAndSetProperty) { HandleScope scope(isolate); RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); @@ -5565,31 +5648,35 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) { (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); attributes = static_cast<PropertyAttributes>(unchecked_value); } - Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes( - object, name, value, attributes); - RETURN_IF_EMPTY_HANDLE(isolate, result); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + JSObject::SetOwnPropertyIgnoreAttributes( + object, name, value, attributes)); return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) { +RUNTIME_FUNCTION(Runtime_DeleteProperty) { HandleScope scope(isolate); ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2); - JSReceiver::DeleteMode delete_mode = (strict_mode == kStrictMode) + JSReceiver::DeleteMode delete_mode = strict_mode == STRICT ? JSReceiver::STRICT_DELETION : JSReceiver::NORMAL_DELETION; - Handle<Object> result = JSReceiver::DeleteProperty(object, key, delete_mode); - RETURN_IF_EMPTY_HANDLE(isolate, result); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + JSReceiver::DeleteProperty(object, key, delete_mode)); return *result; } -static MaybeObject* HasLocalPropertyImplementation(Isolate* isolate, - Handle<JSObject> object, - Handle<Name> key) { - if (JSReceiver::HasLocalProperty(object, key)) { +static Object* HasOwnPropertyImplementation(Isolate* isolate, + Handle<JSObject> object, + Handle<Name> key) { + if (JSReceiver::HasOwnProperty(object, key)) { return isolate->heap()->true_value(); } // Handle hidden prototypes. If there's a hidden prototype above this thing @@ -5598,20 +5685,20 @@ static MaybeObject* HasLocalPropertyImplementation(Isolate* isolate, Handle<Object> proto(object->GetPrototype(), isolate); if (proto->IsJSObject() && Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) { - return HasLocalPropertyImplementation(isolate, - Handle<JSObject>::cast(proto), - key); + return HasOwnPropertyImplementation(isolate, + Handle<JSObject>::cast(proto), + key); } - RETURN_IF_SCHEDULED_EXCEPTION(isolate); + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); return isolate->heap()->false_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) { +RUNTIME_FUNCTION(Runtime_HasOwnProperty) { HandleScope scope(isolate); ASSERT(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(Object, object, 0) CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); - Handle<Object> object = args.at<Object>(0); uint32_t index; const bool key_is_array_index = key->AsArrayIndex(&index); @@ -5626,7 +5713,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) { ASSERT(!isolate->has_scheduled_exception()); return isolate->heap()->true_value(); } else { - RETURN_IF_SCHEDULED_EXCEPTION(isolate); + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); } Map* map = js_obj->map(); if (!key_is_array_index && @@ -5635,9 +5722,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) { return isolate->heap()->false_value(); } // Slow case. - return HasLocalPropertyImplementation(isolate, - Handle<JSObject>(js_obj), - Handle<Name>(key)); + return HasOwnPropertyImplementation(isolate, + Handle<JSObject>(js_obj), + Handle<Name>(key)); } else if (object->IsString() && key_is_array_index) { // Well, there is one exception: Handle [] on strings. Handle<String> string = Handle<String>::cast(object); @@ -5649,42 +5736,41 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) { +RUNTIME_FUNCTION(Runtime_HasProperty) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); bool result = JSReceiver::HasProperty(receiver, key); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - if (isolate->has_pending_exception()) return Failure::Exception(); + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); + if (isolate->has_pending_exception()) return isolate->heap()->exception(); return isolate->heap()->ToBoolean(result); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) { +RUNTIME_FUNCTION(Runtime_HasElement) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); CONVERT_SMI_ARG_CHECKED(index, 1); bool result = JSReceiver::HasElement(receiver, index); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - if (isolate->has_pending_exception()) return Failure::Exception(); + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); return isolate->heap()->ToBoolean(result); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_IsPropertyEnumerable) { + HandleScope scope(isolate); ASSERT(args.length() == 2); - CONVERT_ARG_CHECKED(JSObject, object, 0); - CONVERT_ARG_CHECKED(Name, key, 1); + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); + CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); - PropertyAttributes att = object->GetLocalPropertyAttribute(key); + PropertyAttributes att = JSReceiver::GetOwnPropertyAttributes(object, key); if (att == ABSENT || (att & DONT_ENUM) != 0) { - RETURN_IF_SCHEDULED_EXCEPTION(isolate); + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); return isolate->heap()->false_value(); } ASSERT(!isolate->has_scheduled_exception()); @@ -5692,14 +5778,18 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) { +RUNTIME_FUNCTION(Runtime_GetPropertyNames) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); - bool threw = false; - Handle<JSArray> result = GetKeysFor(object, &threw); - if (threw) return Failure::Exception(); - return *result; + Handle<JSArray> result; + + isolate->counters()->for_in()->Increment(); + Handle<FixedArray> elements; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, elements, + JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS)); + return *isolate->factory()->NewJSArrayWithElements(elements); } @@ -5708,7 +5798,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) { // all enumerable properties of the object and its prototypes // have none, the map of the object. This is used to speed up // the check for deletions during a for-in. -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) { +RUNTIME_FUNCTION(Runtime_GetPropertyNamesFast) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); @@ -5718,10 +5808,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) { HandleScope scope(isolate); Handle<JSReceiver> object(raw_object); - bool threw = false; - Handle<FixedArray> content = - GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw); - if (threw) return Failure::Exception(); + Handle<FixedArray> content; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, content, + JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS)); // Test again, since cache may have been built by preceding call. if (object->IsSimpleEnum()) return object->map(); @@ -5730,10 +5820,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) { } -// Find the length of the prototype chain that is to to handled as one. If a +// Find the length of the prototype chain that is to be handled as one. If a // prototype object is hidden it is to be viewed as part of the the object it // is prototype for. -static int LocalPrototypeChainLength(JSObject* obj) { +static int OwnPrototypeChainLength(JSObject* obj) { int count = 1; Object* proto = obj->GetPrototype(); while (proto->IsJSObject() && @@ -5745,53 +5835,52 @@ static int LocalPrototypeChainLength(JSObject* obj) { } -// Return the names of the local named properties. +// Return the names of the own named properties. // args[0]: object -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) { +// args[1]: PropertyAttributes as int +RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) { HandleScope scope(isolate); ASSERT(args.length() == 2); if (!args[0]->IsJSObject()) { return isolate->heap()->undefined_value(); } CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); - CONVERT_BOOLEAN_ARG_CHECKED(include_symbols, 1); - PropertyAttributes filter = include_symbols ? NONE : SYMBOLIC; + CONVERT_SMI_ARG_CHECKED(filter_value, 1); + PropertyAttributes filter = static_cast<PropertyAttributes>(filter_value); // Skip the global proxy as it has no properties and always delegates to the // real global object. if (obj->IsJSGlobalProxy()) { // Only collect names if access is permitted. if (obj->IsAccessCheckNeeded() && - !isolate->MayNamedAccess(*obj, - isolate->heap()->undefined_value(), - v8::ACCESS_KEYS)) { - isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); + !isolate->MayNamedAccess( + obj, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) { + isolate->ReportFailedAccessCheck(obj, v8::ACCESS_KEYS); + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); return *isolate->factory()->NewJSArray(0); } obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype())); } // Find the number of objects making up this. - int length = LocalPrototypeChainLength(*obj); + int length = OwnPrototypeChainLength(*obj); - // Find the number of local properties for each of the objects. - ScopedVector<int> local_property_count(length); + // Find the number of own properties for each of the objects. + ScopedVector<int> own_property_count(length); int total_property_count = 0; Handle<JSObject> jsproto = obj; for (int i = 0; i < length; i++) { // Only collect names if access is permitted. if (jsproto->IsAccessCheckNeeded() && - !isolate->MayNamedAccess(*jsproto, - isolate->heap()->undefined_value(), - v8::ACCESS_KEYS)) { - isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); + !isolate->MayNamedAccess( + jsproto, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) { + isolate->ReportFailedAccessCheck(jsproto, v8::ACCESS_KEYS); + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); return *isolate->factory()->NewJSArray(0); } int n; - n = jsproto->NumberOfLocalProperties(filter); - local_property_count[i] = n; + n = jsproto->NumberOfOwnProperties(filter); + own_property_count[i] = n; total_property_count += n; if (i < length - 1) { jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); @@ -5804,41 +5893,66 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) { // Get the property names. jsproto = obj; - int proto_with_hidden_properties = 0; int next_copy_index = 0; + int hidden_strings = 0; for (int i = 0; i < length; i++) { - jsproto->GetLocalPropertyNames(*names, next_copy_index, filter); - next_copy_index += local_property_count[i]; - if (jsproto->HasHiddenProperties()) { - proto_with_hidden_properties++; + jsproto->GetOwnPropertyNames(*names, next_copy_index, filter); + if (i > 0) { + // Names from hidden prototypes may already have been added + // for inherited function template instances. Count the duplicates + // and stub them out; the final copy pass at the end ignores holes. + for (int j = next_copy_index; + j < next_copy_index + own_property_count[i]; + j++) { + Object* name_from_hidden_proto = names->get(j); + for (int k = 0; k < next_copy_index; k++) { + if (names->get(k) != isolate->heap()->hidden_string()) { + Object* name = names->get(k); + if (name_from_hidden_proto == name) { + names->set(j, isolate->heap()->hidden_string()); + hidden_strings++; + break; + } + } + } + } + } + next_copy_index += own_property_count[i]; + + // Hidden properties only show up if the filter does not skip strings. + if ((filter & STRING) == 0 && JSObject::HasHiddenProperties(jsproto)) { + hidden_strings++; } if (i < length - 1) { jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); } } - // Filter out name of hidden properties object. - if (proto_with_hidden_properties > 0) { + // Filter out name of hidden properties object and + // hidden prototype duplicates. + if (hidden_strings > 0) { Handle<FixedArray> old_names = names; names = isolate->factory()->NewFixedArray( - names->length() - proto_with_hidden_properties); + names->length() - hidden_strings); int dest_pos = 0; for (int i = 0; i < total_property_count; i++) { Object* name = old_names->get(i); if (name == isolate->heap()->hidden_string()) { + hidden_strings--; continue; } names->set(dest_pos++, name); } + ASSERT_EQ(0, hidden_strings); } return *isolate->factory()->NewJSArrayWithElements(names); } -// Return the names of the local indexed properties. +// Return the names of the own indexed properties. // args[0]: object -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) { +RUNTIME_FUNCTION(Runtime_GetOwnElementNames) { HandleScope scope(isolate); ASSERT(args.length() == 1); if (!args[0]->IsJSObject()) { @@ -5846,16 +5960,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) { } CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); - int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE)); + int n = obj->NumberOfOwnElements(static_cast<PropertyAttributes>(NONE)); Handle<FixedArray> names = isolate->factory()->NewFixedArray(n); - obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE)); + obj->GetOwnElementKeys(*names, static_cast<PropertyAttributes>(NONE)); return *isolate->factory()->NewJSArrayWithElements(names); } // Return information on whether an object has a named or indexed interceptor. // args[0]: object -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) { +RUNTIME_FUNCTION(Runtime_GetInterceptorInfo) { HandleScope scope(isolate); ASSERT(args.length() == 1); if (!args[0]->IsJSObject()) { @@ -5873,14 +5987,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) { // Return property names from named interceptor. // args[0]: object -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) { +RUNTIME_FUNCTION(Runtime_GetNamedInterceptorPropertyNames) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); if (obj->HasNamedInterceptor()) { - v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj); - if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); + Handle<JSObject> result; + if (JSObject::GetKeysForNamedInterceptor(obj, obj).ToHandle(&result)) { + return *result; + } } return isolate->heap()->undefined_value(); } @@ -5888,32 +6004,34 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) { // Return element names from indexed interceptor. // args[0]: object -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) { +RUNTIME_FUNCTION(Runtime_GetIndexedInterceptorElementNames) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); if (obj->HasIndexedInterceptor()) { - v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj); - if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); + Handle<JSObject> result; + if (JSObject::GetKeysForIndexedInterceptor(obj, obj).ToHandle(&result)) { + return *result; + } } return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) { +RUNTIME_FUNCTION(Runtime_OwnKeys) { HandleScope scope(isolate); - ASSERT_EQ(args.length(), 1); + ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSObject, raw_object, 0); Handle<JSObject> object(raw_object); if (object->IsJSGlobalProxy()) { // Do access checks before going to the global object. if (object->IsAccessCheckNeeded() && - !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(), - v8::ACCESS_KEYS)) { - isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); + !isolate->MayNamedAccess( + object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) { + isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS); + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); return *isolate->factory()->NewJSArray(0); } @@ -5923,10 +6041,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) { object = Handle<JSObject>::cast(proto); } - bool threw = false; - Handle<FixedArray> contents = - GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw); - if (threw) return Failure::Exception(); + Handle<FixedArray> contents; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, contents, + JSReceiver::GetKeys(object, JSReceiver::OWN_ONLY)); // Some fast paths through GetKeysInFixedArrayFor reuse a cached // property array and since the result is mutable we have to create @@ -5950,9 +6068,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) { +RUNTIME_FUNCTION(Runtime_GetArgumentsProperty) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(Object, raw_key, 0); // Compute the frame holding the arguments. JavaScriptFrameIterator it(isolate); @@ -5965,22 +6084,25 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) { // Try to convert the key to an index. If successful and within // index return the the argument from the frame. uint32_t index; - if (args[0]->ToArrayIndex(&index) && index < n) { + if (raw_key->ToArrayIndex(&index) && index < n) { return frame->GetParameter(index); } - if (args[0]->IsSymbol()) { + HandleScope scope(isolate); + if (raw_key->IsSymbol()) { // Lookup in the initial Object.prototype object. - return isolate->initial_object_prototype()->GetProperty( - Symbol::cast(args[0])); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + Object::GetProperty(isolate->initial_object_prototype(), + Handle<Symbol>::cast(raw_key))); + return *result; } // Convert the key to a string. - HandleScope scope(isolate); - bool exception = false; - Handle<Object> converted = - Execution::ToString(isolate, args.at<Object>(0), &exception); - if (exception) return Failure::Exception(); + Handle<Object> converted; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, converted, Execution::ToString(isolate, raw_key)); Handle<String> key = Handle<String>::cast(converted); // Try to convert the string key into an array index. @@ -5988,15 +6110,22 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) { if (index < n) { return frame->GetParameter(index); } else { - return isolate->initial_object_prototype()->GetElement(isolate, index); + Handle<Object> initial_prototype(isolate->initial_object_prototype()); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + Object::GetElement(isolate, initial_prototype, index)); + return *result; } } // Handle special arguments properties. - if (key->Equals(isolate->heap()->length_string())) return Smi::FromInt(n); - if (key->Equals(isolate->heap()->callee_string())) { + if (String::Equals(isolate->factory()->length_string(), key)) { + return Smi::FromInt(n); + } + if (String::Equals(isolate->factory()->callee_string(), key)) { JSFunction* function = frame->function(); - if (!function->shared()->is_classic_mode()) { + if (function->shared()->strict_mode() == STRICT) { return isolate->Throw(*isolate->factory()->NewTypeError( "strict_arguments_callee", HandleVector<Object>(NULL, 0))); } @@ -6004,11 +6133,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) { } // Lookup in the initial Object.prototype object. - return isolate->initial_object_prototype()->GetProperty(*key); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + Object::GetProperty(isolate->initial_object_prototype(), key)); + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) { +RUNTIME_FUNCTION(Runtime_ToFastProperties) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); @@ -6019,20 +6152,21 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) { +RUNTIME_FUNCTION(Runtime_ToBool) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); + CONVERT_ARG_CHECKED(Object, object, 0); - return isolate->heap()->ToBoolean(args[0]->BooleanValue()); + return isolate->heap()->ToBoolean(object->BooleanValue()); } // Returns the type string of a value; see ECMA-262, 11.4.3 (p 47). // Possible optimizations: put the type string into the oddballs. -RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) { +RUNTIME_FUNCTION(Runtime_Typeof) { SealHandleScope shs(isolate); - - Object* obj = args[0]; + ASSERT(args.length() == 1); + CONVERT_ARG_CHECKED(Object, obj, 0); if (obj->IsNumber()) return isolate->heap()->number_string(); HeapObject* heap_obj = HeapObject::cast(obj); @@ -6093,18 +6227,19 @@ static int ParseDecimalInteger(const uint8_t*s, int from, int to) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_StringToNumber) { + HandleScope handle_scope(isolate); ASSERT(args.length() == 1); - CONVERT_ARG_CHECKED(String, subject, 0); - subject->TryFlatten(); + CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); + subject = String::Flatten(subject); // Fast case: short integer or some sorts of junk values. - int len = subject->length(); if (subject->IsSeqOneByteString()) { + int len = subject->length(); if (len == 0) return Smi::FromInt(0); - uint8_t const* data = SeqOneByteString::cast(subject)->GetChars(); + DisallowHeapAllocation no_gc; + uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars(); bool minus = (data[0] == '-'); int start_pos = (minus ? 1 : 0); @@ -6112,15 +6247,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) { return isolate->heap()->nan_value(); } else if (data[start_pos] > '9') { // Fast check for a junk value. A valid string may start from a - // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or - // the 'I' character ('Infinity'). All of that have codes not greater than - // '9' except 'I' and . + // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit + // or the 'I' character ('Infinity'). All of that have codes not greater + // than '9' except 'I' and . if (data[start_pos] != 'I' && data[start_pos] != 0xa0) { return isolate->heap()->nan_value(); } } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) { - // The maximal/minimal smi has 10 digits. If the string has less digits we - // know it will fit into the smi-data type. + // The maximal/minimal smi has 10 digits. If the string has less digits + // we know it will fit into the smi-data type. int d = ParseDecimalInteger(data, start_pos, len); if (minus) { if (d == 0) return isolate->heap()->minus_zero_value(); @@ -6149,144 +6284,173 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) { // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584 flags |= ALLOW_OCTAL | ALLOW_BINARY; } - return isolate->heap()->NumberFromDouble( - StringToDouble(isolate->unicode_cache(), subject, flags)); + + return *isolate->factory()->NewNumber(StringToDouble( + isolate->unicode_cache(), *subject, flags)); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NewString) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NewString) { + HandleScope scope(isolate); + ASSERT(args.length() == 2); CONVERT_SMI_ARG_CHECKED(length, 0); CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1); if (length == 0) return isolate->heap()->empty_string(); + Handle<String> result; if (is_one_byte) { - return isolate->heap()->AllocateRawOneByteString(length); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, isolate->factory()->NewRawOneByteString(length)); } else { - return isolate->heap()->AllocateRawTwoByteString(length); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, isolate->factory()->NewRawTwoByteString(length)); } + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_TruncateString) { +RUNTIME_FUNCTION(Runtime_TruncateString) { HandleScope scope(isolate); + ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0); CONVERT_SMI_ARG_CHECKED(new_length, 1); + RUNTIME_ASSERT(new_length >= 0); return *SeqString::Truncate(string, new_length); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) { +RUNTIME_FUNCTION(Runtime_URIEscape) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(String, source, 0); - Handle<String> string = FlattenGetString(source); + Handle<String> string = String::Flatten(source); ASSERT(string->IsFlat()); - Handle<String> result = string->IsOneByteRepresentationUnderneath() - ? URIEscape::Escape<uint8_t>(isolate, source) - : URIEscape::Escape<uc16>(isolate, source); - if (result.is_null()) return Failure::OutOfMemoryException(0x12); + Handle<String> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + string->IsOneByteRepresentationUnderneath() + ? URIEscape::Escape<uint8_t>(isolate, source) + : URIEscape::Escape<uc16>(isolate, source)); return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) { +RUNTIME_FUNCTION(Runtime_URIUnescape) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(String, source, 0); - Handle<String> string = FlattenGetString(source); + Handle<String> string = String::Flatten(source); ASSERT(string->IsFlat()); - return string->IsOneByteRepresentationUnderneath() - ? *URIUnescape::Unescape<uint8_t>(isolate, source) - : *URIUnescape::Unescape<uc16>(isolate, source); + Handle<String> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + string->IsOneByteRepresentationUnderneath() + ? URIUnescape::Unescape<uint8_t>(isolate, source) + : URIUnescape::Unescape<uc16>(isolate, source)); + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) { +RUNTIME_FUNCTION(Runtime_QuoteJSONString) { HandleScope scope(isolate); CONVERT_ARG_HANDLE_CHECKED(String, string, 0); ASSERT(args.length() == 1); - return BasicJsonStringifier::StringifyString(isolate, string); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, BasicJsonStringifier::StringifyString(isolate, string)); + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_BasicJSONStringify) { +RUNTIME_FUNCTION(Runtime_BasicJSONStringify) { HandleScope scope(isolate); ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); BasicJsonStringifier stringifier(isolate); - return stringifier.Stringify(Handle<Object>(args[0], isolate)); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, stringifier.Stringify(object)); + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_StringParseInt) { + HandleScope handle_scope(isolate); + ASSERT(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); + CONVERT_NUMBER_CHECKED(int, radix, Int32, args[1]); + RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); - CONVERT_ARG_CHECKED(String, s, 0); - CONVERT_SMI_ARG_CHECKED(radix, 1); + subject = String::Flatten(subject); + double value; - s->TryFlatten(); + { DisallowHeapAllocation no_gc; + String::FlatContent flat = subject->GetFlatContent(); - RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); - double value = StringToInt(isolate->unicode_cache(), s, radix); - return isolate->heap()->NumberFromDouble(value); + // ECMA-262 section 15.1.2.3, empty string is NaN + if (flat.IsAscii()) { + value = StringToInt( + isolate->unicode_cache(), flat.ToOneByteVector(), radix); + } else { + value = StringToInt( + isolate->unicode_cache(), flat.ToUC16Vector(), radix); + } + } + + return *isolate->factory()->NewNumber(value); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) { - SealHandleScope shs(isolate); - CONVERT_ARG_CHECKED(String, str, 0); +RUNTIME_FUNCTION(Runtime_StringParseFloat) { + HandleScope shs(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); - // ECMA-262 section 15.1.2.3, empty string is NaN - double value = StringToDouble(isolate->unicode_cache(), - str, ALLOW_TRAILING_JUNK, OS::nan_value()); + subject = String::Flatten(subject); + double value = StringToDouble( + isolate->unicode_cache(), *subject, ALLOW_TRAILING_JUNK, OS::nan_value()); - // Create a number object from the value. - return isolate->heap()->NumberFromDouble(value); + return *isolate->factory()->NewNumber(value); +} + + +static inline bool ToUpperOverflows(uc32 character) { + // y with umlauts and the micro sign are the only characters that stop + // fitting into one-byte when converting to uppercase. + static const uc32 yuml_code = 0xff; + static const uc32 micro_code = 0xb5; + return (character == yuml_code || character == micro_code); } template <class Converter> -MUST_USE_RESULT static MaybeObject* ConvertCaseHelper( +MUST_USE_RESULT static Object* ConvertCaseHelper( Isolate* isolate, - String* s, - String::Encoding result_encoding, - int length, - int input_string_length, + String* string, + SeqString* result, + int result_length, unibrow::Mapping<Converter, 128>* mapping) { + DisallowHeapAllocation no_gc; // We try this twice, once with the assumption that the result is no longer // than the input and, if that assumption breaks, again with the exact // length. This may not be pretty, but it is nicer than what was here before // and I hereby claim my vaffel-is. // - // Allocate the resulting string. - // // NOTE: This assumes that the upper/lower case of an ASCII // character is also ASCII. This is currently the case, but it // might break in the future if we implement more context and locale // dependent upper/lower conversions. - Object* o; - { MaybeObject* maybe_o = result_encoding == String::ONE_BYTE_ENCODING - ? isolate->heap()->AllocateRawOneByteString(length) - : isolate->heap()->AllocateRawTwoByteString(length); - if (!maybe_o->ToObject(&o)) return maybe_o; - } - String* result = String::cast(o); bool has_changed_character = false; - DisallowHeapAllocation no_gc; - // Convert all characters to upper case, assuming that they will fit // in the buffer Access<ConsStringIteratorOp> op( isolate->runtime_state()->string_iterator()); - StringCharacterStream stream(s, op.value()); + StringCharacterStream stream(string, op.value()); unibrow::uchar chars[Converter::kMaxWidth]; // We can assume that the string is not empty uc32 current = stream.GetNext(); - // y with umlauts is the only character that stops fitting into one-byte - // when converting to uppercase. - static const uc32 yuml_code = 0xff; - bool ignore_yuml = result->IsSeqTwoByteString() || Converter::kIsToLower; - for (int i = 0; i < length;) { + bool ignore_overflow = Converter::kIsToLower || result->IsSeqTwoByteString(); + for (int i = 0; i < result_length;) { bool has_next = stream.HasMore(); uc32 next = has_next ? stream.GetNext() : 0; int char_length = mapping->get(current, next, chars); @@ -6294,14 +6458,15 @@ MUST_USE_RESULT static MaybeObject* ConvertCaseHelper( // The case conversion of this character is the character itself. result->Set(i, current); i++; - } else if (char_length == 1 && (ignore_yuml || current != yuml_code)) { + } else if (char_length == 1 && + (ignore_overflow || !ToUpperOverflows(current))) { // Common case: converting the letter resulted in one character. ASSERT(static_cast<uc32>(chars[0]) != current); result->Set(i, chars[0]); has_changed_character = true; i++; - } else if (length == input_string_length) { - bool found_yuml = (current == yuml_code); + } else if (result_length == string->length()) { + bool overflows = ToUpperOverflows(current); // We've assumed that the result would be as long as the // input but here is a character that converts to several // characters. No matter, we calculate the exact length @@ -6321,7 +6486,7 @@ MUST_USE_RESULT static MaybeObject* ConvertCaseHelper( int current_length = i + char_length + next_length; while (stream.HasMore()) { current = stream.GetNext(); - found_yuml |= (current == yuml_code); + overflows |= ToUpperOverflows(current); // NOTE: we use 0 as the next character here because, while // the next character may affect what a character converts to, // it does not in any case affect the length of what it convert @@ -6329,15 +6494,15 @@ MUST_USE_RESULT static MaybeObject* ConvertCaseHelper( int char_length = mapping->get(current, 0, chars); if (char_length == 0) char_length = 1; current_length += char_length; - if (current_length > Smi::kMaxValue) { - isolate->context()->mark_out_of_memory(); - return Failure::OutOfMemoryException(0x13); + if (current_length > String::kMaxLength) { + AllowHeapAllocation allocate_error_and_return; + return isolate->ThrowInvalidStringLength(); } } // Try again with the real length. Return signed if we need - // to allocate a two-byte string for y-umlaut to uppercase. - return (found_yuml && !ignore_yuml) ? Smi::FromInt(-current_length) - : Smi::FromInt(current_length); + // to allocate a two-byte string for to uppercase. + return (overflows && !ignore_overflow) ? Smi::FromInt(-current_length) + : Smi::FromInt(current_length); } else { for (int j = 0; j < char_length; j++) { result->Set(i, chars[j]); @@ -6354,7 +6519,7 @@ MUST_USE_RESULT static MaybeObject* ConvertCaseHelper( // we simple return the result and let the converted string // become garbage; there is no reason to keep two identical strings // alive. - return s; + return string; } } @@ -6385,7 +6550,7 @@ static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) { #ifdef DEBUG static bool CheckFastAsciiConvert(char* dst, - char* src, + const char* src, int length, bool changed, bool is_to_lower) { @@ -6408,12 +6573,12 @@ static bool CheckFastAsciiConvert(char* dst, template<class Converter> static bool FastAsciiConvert(char* dst, - char* src, + const char* src, int length, bool* changed_out) { #ifdef DEBUG char* saved_dst = dst; - char* saved_src = src; + const char* saved_src = src; #endif DisallowHeapAllocation no_gc; // We rely on the distance between upper and lower case letters @@ -6424,12 +6589,12 @@ static bool FastAsciiConvert(char* dst, static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1; bool changed = false; uintptr_t or_acc = 0; - char* const limit = src + length; + const char* const limit = src + length; #ifdef V8_HOST_CAN_READ_UNALIGNED // Process the prefix of the input that requires no conversion one // (machine) word at a time. while (src <= limit - sizeof(uintptr_t)) { - uintptr_t w = *reinterpret_cast<uintptr_t*>(src); + const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src); or_acc |= w; if (AsciiRangeMask(w, lo, hi) != 0) { changed = true; @@ -6442,7 +6607,7 @@ static bool FastAsciiConvert(char* dst, // Process the remainder of the input performing conversion when // required one word at a time. while (src <= limit - sizeof(uintptr_t)) { - uintptr_t w = *reinterpret_cast<uintptr_t*>(src); + const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src); or_acc |= w; uintptr_t m = AsciiRangeMask(w, lo, hi); // The mask has high (7th) bit set in every byte that needs @@ -6481,17 +6646,14 @@ static bool FastAsciiConvert(char* dst, template <class Converter> -MUST_USE_RESULT static MaybeObject* ConvertCase( - Arguments args, +MUST_USE_RESULT static Object* ConvertCase( + Handle<String> s, Isolate* isolate, unibrow::Mapping<Converter, 128>* mapping) { - SealHandleScope shs(isolate); - CONVERT_ARG_CHECKED(String, s, 0); - s = s->TryFlattenGetString(); - - const int length = s->length(); + s = String::Flatten(s); + int length = s->length(); // Assume that the string is not empty; we need this assumption later - if (length == 0) return s; + if (length == 0) return *s; // Simpler handling of ASCII strings. // @@ -6499,96 +6661,105 @@ MUST_USE_RESULT static MaybeObject* ConvertCase( // character is also ASCII. This is currently the case, but it // might break in the future if we implement more context and locale // dependent upper/lower conversions. - if (s->IsSeqOneByteString()) { - Object* o; - { MaybeObject* maybe_o = isolate->heap()->AllocateRawOneByteString(length); - if (!maybe_o->ToObject(&o)) return maybe_o; - } - SeqOneByteString* result = SeqOneByteString::cast(o); - bool has_changed_character; + if (s->IsOneByteRepresentationUnderneath()) { + // Same length as input. + Handle<SeqOneByteString> result = + isolate->factory()->NewRawOneByteString(length).ToHandleChecked(); + DisallowHeapAllocation no_gc; + String::FlatContent flat_content = s->GetFlatContent(); + ASSERT(flat_content.IsFlat()); + bool has_changed_character = false; bool is_ascii = FastAsciiConvert<Converter>( reinterpret_cast<char*>(result->GetChars()), - reinterpret_cast<char*>(SeqOneByteString::cast(s)->GetChars()), + reinterpret_cast<const char*>(flat_content.ToOneByteVector().start()), length, &has_changed_character); // If not ASCII, we discard the result and take the 2 byte path. - if (is_ascii) { - return has_changed_character ? result : s; - } + if (is_ascii) return has_changed_character ? *result : *s; } - String::Encoding result_encoding = s->IsOneByteRepresentation() - ? String::ONE_BYTE_ENCODING : String::TWO_BYTE_ENCODING; - Object* answer; - { MaybeObject* maybe_answer = ConvertCaseHelper( - isolate, s, result_encoding, length, length, mapping); - if (!maybe_answer->ToObject(&answer)) return maybe_answer; - } - if (answer->IsSmi()) { - int new_length = Smi::cast(answer)->value(); - if (new_length < 0) { - result_encoding = String::TWO_BYTE_ENCODING; - new_length = -new_length; - } - MaybeObject* maybe_answer = ConvertCaseHelper( - isolate, s, result_encoding, new_length, length, mapping); - if (!maybe_answer->ToObject(&answer)) return maybe_answer; + Handle<SeqString> result; // Same length as input. + if (s->IsOneByteRepresentation()) { + result = isolate->factory()->NewRawOneByteString(length).ToHandleChecked(); + } else { + result = isolate->factory()->NewRawTwoByteString(length).ToHandleChecked(); } - return answer; -} + Object* answer = ConvertCaseHelper(isolate, *s, *result, length, mapping); + if (answer->IsException() || answer->IsString()) return answer; -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) { - return ConvertCase( - args, isolate, isolate->runtime_state()->to_lower_mapping()); + ASSERT(answer->IsSmi()); + length = Smi::cast(answer)->value(); + if (s->IsOneByteRepresentation() && length > 0) { + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, isolate->factory()->NewRawOneByteString(length)); + } else { + if (length < 0) length = -length; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, isolate->factory()->NewRawTwoByteString(length)); + } + return ConvertCaseHelper(isolate, *s, *result, length, mapping); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) { +RUNTIME_FUNCTION(Runtime_StringToLowerCase) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(String, s, 0); return ConvertCase( - args, isolate, isolate->runtime_state()->to_upper_mapping()); + s, isolate, isolate->runtime_state()->to_lower_mapping()); } -static inline bool IsTrimWhiteSpace(unibrow::uchar c) { - return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff; +RUNTIME_FUNCTION(Runtime_StringToUpperCase) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(String, s, 0); + return ConvertCase( + s, isolate, isolate->runtime_state()->to_upper_mapping()); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_StringTrim) { + HandleScope scope(isolate); ASSERT(args.length() == 3); - CONVERT_ARG_CHECKED(String, s, 0); + CONVERT_ARG_HANDLE_CHECKED(String, string, 0); CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1); CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2); - s->TryFlatten(); - int length = s->length(); + string = String::Flatten(string); + int length = string->length(); int left = 0; + UnicodeCache* unicode_cache = isolate->unicode_cache(); if (trimLeft) { - while (left < length && IsTrimWhiteSpace(s->Get(left))) { + while (left < length && + unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) { left++; } } int right = length; if (trimRight) { - while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) { + while (right > left && + unicode_cache->IsWhiteSpaceOrLineTerminator( + string->Get(right - 1))) { right--; } } - return s->SubString(left, right); + + return *isolate->factory()->NewSubString(string, left, right); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) { +RUNTIME_FUNCTION(Runtime_StringSplit) { HandleScope handle_scope(isolate); ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]); + RUNTIME_ASSERT(limit > 0); int subject_length = subject->length(); int pattern_length = pattern->length(); @@ -6614,7 +6785,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) { // isn't empty, we can never create more parts than ~half the length // of the subject. - if (!subject->IsFlat()) FlattenString(subject); + subject = String::Flatten(subject); + pattern = String::Flatten(pattern); static const int kMaxInitialListCapacity = 16; @@ -6623,7 +6795,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) { // Find (up to limit) indices of separator and end-of-string in subject int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit); ZoneList<int> indices(initial_capacity, zone_scope.zone()); - if (!pattern->IsFlat()) FlattenString(pattern); FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit, zone_scope.zone()); @@ -6661,10 +6832,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) { if (limit == 0xffffffffu) { if (result->HasFastObjectElements()) { - RegExpResultsCache::Enter(isolate->heap(), - *subject, - *pattern, - *elements, + RegExpResultsCache::Enter(isolate, + subject, + pattern, + elements, RegExpResultsCache::STRING_SPLIT_SUBSTRINGS); } } @@ -6708,25 +6879,21 @@ static int CopyCachedAsciiCharsToArray(Heap* heap, // Converts a String to JSArray. // For example, "foo" => ["f", "o", "o"]. -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) { +RUNTIME_FUNCTION(Runtime_StringToArray) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(String, s, 0); CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); - s = FlattenGetString(s); + s = String::Flatten(s); const int length = static_cast<int>(Min<uint32_t>(s->length(), limit)); Handle<FixedArray> elements; int position = 0; if (s->IsFlat() && s->IsOneByteRepresentation()) { // Try using cached chars where possible. - Object* obj; - { MaybeObject* maybe_obj = - isolate->heap()->AllocateUninitializedFixedArray(length); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } - elements = Handle<FixedArray>(FixedArray::cast(obj), isolate); + elements = isolate->factory()->NewUninitializedFixedArray(length); + DisallowHeapAllocation no_gc; String::FlatContent content = s->GetFlatContent(); if (content.IsAscii()) { @@ -6747,7 +6914,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) { } for (int i = position; i < length; ++i) { Handle<Object> str = - LookupSingleCharacterStringFromCode(isolate, s->Get(i)); + isolate->factory()->LookupSingleCharacterStringFromCode(s->Get(i)); elements->set(i, *str); } @@ -6761,11 +6928,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NewStringWrapper) { + HandleScope scope(isolate); ASSERT(args.length() == 1); - CONVERT_ARG_CHECKED(String, value, 0); - return value->ToObject(isolate); + CONVERT_ARG_HANDLE_CHECKED(String, value, 0); + return *Object::ToObject(isolate, value).ToHandleChecked(); } @@ -6776,110 +6943,70 @@ bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) { - SealHandleScope shs(isolate); - ASSERT(args.length() == 1); - - Object* number = args[0]; - RUNTIME_ASSERT(number->IsNumber()); - - return isolate->heap()->NumberToString(number); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_NumberToString) { + HandleScope scope(isolate); ASSERT(args.length() == 1); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0); - Object* number = args[0]; - RUNTIME_ASSERT(number->IsNumber()); - - return isolate->heap()->NumberToString( - number, false, isolate->heap()->GetPretenureMode()); + return *isolate->factory()->NumberToString(number); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_NumberToStringSkipCache) { + HandleScope scope(isolate); ASSERT(args.length() == 1); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0); - CONVERT_DOUBLE_ARG_CHECKED(number, 0); - - // We do not include 0 so that we don't have to treat +0 / -0 cases. - if (number > 0 && number <= Smi::kMaxValue) { - return Smi::FromInt(static_cast<int>(number)); - } - return isolate->heap()->NumberFromDouble(DoubleToInteger(number)); + return *isolate->factory()->NumberToString(number, false); } -// ES6 draft 9.1.11 -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPositiveInteger) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberToInteger) { + HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_DOUBLE_ARG_CHECKED(number, 0); - - // We do not include 0 so that we don't have to treat +0 / -0 cases. - if (number > 0 && number <= Smi::kMaxValue) { - return Smi::FromInt(static_cast<int>(number)); - } - if (number <= 0) { - return Smi::FromInt(0); - } - return isolate->heap()->NumberFromDouble(DoubleToInteger(number)); + return *isolate->factory()->NewNumber(DoubleToInteger(number)); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberToIntegerMapMinusZero) { + HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_DOUBLE_ARG_CHECKED(number, 0); - - // We do not include 0 so that we don't have to treat +0 / -0 cases. - if (number > 0 && number <= Smi::kMaxValue) { - return Smi::FromInt(static_cast<int>(number)); - } - double double_value = DoubleToInteger(number); // Map both -0 and +0 to +0. if (double_value == 0) double_value = 0; - return isolate->heap()->NumberFromDouble(double_value); + return *isolate->factory()->NewNumber(double_value); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberToJSUint32) { + HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]); - return isolate->heap()->NumberFromUint32(number); + return *isolate->factory()->NewNumberFromUint(number); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberToJSInt32) { + HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_DOUBLE_ARG_CHECKED(number, 0); - - // We do not include 0 so that we don't have to treat +0 / -0 cases. - if (number > 0 && number <= Smi::kMaxValue) { - return Smi::FromInt(static_cast<int>(number)); - } - return isolate->heap()->NumberFromInt32(DoubleToInt32(number)); + return *isolate->factory()->NewNumberFromInt(DoubleToInt32(number)); } // Converts a Number to a Smi, if possible. Returns NaN if the number is not // a small integer. -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) { +RUNTIME_FUNCTION(RuntimeHidden_NumberToSmi) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); - - Object* obj = args[0]; + CONVERT_ARG_CHECKED(Object, obj, 0); if (obj->IsSmi()) { return obj; } @@ -6894,100 +7021,92 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_AllocateHeapNumber) { + HandleScope scope(isolate); ASSERT(args.length() == 0); - return isolate->heap()->AllocateHeapNumber(0); + return *isolate->factory()->NewHeapNumber(0); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberAdd) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_DOUBLE_ARG_CHECKED(x, 0); CONVERT_DOUBLE_ARG_CHECKED(y, 1); - return isolate->heap()->NumberFromDouble(x + y); + return *isolate->factory()->NewNumber(x + y); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberSub) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_DOUBLE_ARG_CHECKED(x, 0); CONVERT_DOUBLE_ARG_CHECKED(y, 1); - return isolate->heap()->NumberFromDouble(x - y); + return *isolate->factory()->NewNumber(x - y); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberMul) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_DOUBLE_ARG_CHECKED(x, 0); CONVERT_DOUBLE_ARG_CHECKED(y, 1); - return isolate->heap()->NumberFromDouble(x * y); + return *isolate->factory()->NewNumber(x * y); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberUnaryMinus) { + HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_DOUBLE_ARG_CHECKED(x, 0); - return isolate->heap()->NumberFromDouble(-x); + return *isolate->factory()->NewNumber(-x); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) { - SealHandleScope shs(isolate); - ASSERT(args.length() == 0); - - return isolate->heap()->NumberFromDouble(9876543210.0); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberDiv) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_DOUBLE_ARG_CHECKED(x, 0); CONVERT_DOUBLE_ARG_CHECKED(y, 1); - return isolate->heap()->NumberFromDouble(x / y); + return *isolate->factory()->NewNumber(x / y); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberMod) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_DOUBLE_ARG_CHECKED(x, 0); CONVERT_DOUBLE_ARG_CHECKED(y, 1); - - x = modulo(x, y); - // NumberFromDouble may return a Smi instead of a Number object - return isolate->heap()->NumberFromDouble(x); + return *isolate->factory()->NewNumber(modulo(x, y)); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberImul) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberImul) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); - return isolate->heap()->NumberFromInt32(x * y); + return *isolate->factory()->NewNumberFromInt(x * y); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_StringAdd) { + HandleScope scope(isolate); ASSERT(args.length() == 2); - CONVERT_ARG_CHECKED(String, str1, 0); - CONVERT_ARG_CHECKED(String, str2, 1); + CONVERT_ARG_HANDLE_CHECKED(String, str1, 0); + CONVERT_ARG_HANDLE_CHECKED(String, str2, 1); isolate->counters()->string_add_runtime()->Increment(); - return isolate->heap()->AllocateConsString(str1, str2); + Handle<String> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, isolate->factory()->NewConsString(str1, str2)); + return *result; } @@ -6996,6 +7115,7 @@ static inline void StringBuilderConcatHelper(String* special, sinkchar* sink, FixedArray* fixed_array, int array_length) { + DisallowHeapAllocation no_gc; int position = 0; for (int i = 0; i < array_length; i++) { Object* element = fixed_array->get(i); @@ -7030,39 +7150,13 @@ static inline void StringBuilderConcatHelper(String* special, } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) { - HandleScope scope(isolate); - ASSERT(args.length() == 3); - CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); - if (!args[1]->IsSmi()) { - isolate->context()->mark_out_of_memory(); - return Failure::OutOfMemoryException(0x14); - } - int array_length = args.smi_at(1); - CONVERT_ARG_HANDLE_CHECKED(String, special, 2); - - // This assumption is used by the slice encoding in one or two smis. - ASSERT(Smi::kMaxValue >= String::kMaxLength); - - JSObject::EnsureCanContainHeapObjectElements(array); - - int special_length = special->length(); - if (!array->HasFastObjectElements()) { - return isolate->Throw(isolate->heap()->illegal_argument_string()); - } - FixedArray* fixed_array = FixedArray::cast(array->elements()); - if (fixed_array->length() < array_length) { - array_length = fixed_array->length(); - } - - if (array_length == 0) { - return isolate->heap()->empty_string(); - } else if (array_length == 1) { - Object* first = fixed_array->get(0); - if (first->IsString()) return first; - } - - bool one_byte = special->HasOnlyOneByteChars(); +// Returns the result length of the concatenation. +// On illegal argument, -1 is returned. +static inline int StringBuilderConcatLength(int special_length, + FixedArray* fixed_array, + int array_length, + bool* one_byte) { + DisallowHeapAllocation no_gc; int position = 0; for (int i = 0; i < array_length; i++) { int increment = 0; @@ -7081,86 +7175,118 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) { len = -smi_value; // Get the position and check that it is a positive smi. i++; - if (i >= array_length) { - return isolate->Throw(isolate->heap()->illegal_argument_string()); - } + if (i >= array_length) return -1; Object* next_smi = fixed_array->get(i); - if (!next_smi->IsSmi()) { - return isolate->Throw(isolate->heap()->illegal_argument_string()); - } + if (!next_smi->IsSmi()) return -1; pos = Smi::cast(next_smi)->value(); - if (pos < 0) { - return isolate->Throw(isolate->heap()->illegal_argument_string()); - } + if (pos < 0) return -1; } ASSERT(pos >= 0); ASSERT(len >= 0); - if (pos > special_length || len > special_length - pos) { - return isolate->Throw(isolate->heap()->illegal_argument_string()); - } + if (pos > special_length || len > special_length - pos) return -1; increment = len; } else if (elt->IsString()) { String* element = String::cast(elt); int element_length = element->length(); increment = element_length; - if (one_byte && !element->HasOnlyOneByteChars()) { - one_byte = false; + if (*one_byte && !element->HasOnlyOneByteChars()) { + *one_byte = false; } } else { - ASSERT(!elt->IsTheHole()); - return isolate->Throw(isolate->heap()->illegal_argument_string()); + return -1; } if (increment > String::kMaxLength - position) { - isolate->context()->mark_out_of_memory(); - return Failure::OutOfMemoryException(0x15); + return kMaxInt; // Provoke throw on allocation. } position += increment; } + return position; +} - int length = position; - Object* object; - if (one_byte) { - { MaybeObject* maybe_object = - isolate->heap()->AllocateRawOneByteString(length); - if (!maybe_object->ToObject(&object)) return maybe_object; +RUNTIME_FUNCTION(Runtime_StringBuilderConcat) { + HandleScope scope(isolate); + ASSERT(args.length() == 3); + CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); + if (!args[1]->IsSmi()) return isolate->ThrowInvalidStringLength(); + CONVERT_SMI_ARG_CHECKED(array_length, 1); + CONVERT_ARG_HANDLE_CHECKED(String, special, 2); + + size_t actual_array_length = 0; + RUNTIME_ASSERT( + TryNumberToSize(isolate, array->length(), &actual_array_length)); + RUNTIME_ASSERT(array_length >= 0); + RUNTIME_ASSERT(static_cast<size_t>(array_length) <= actual_array_length); + + // This assumption is used by the slice encoding in one or two smis. + ASSERT(Smi::kMaxValue >= String::kMaxLength); + + RUNTIME_ASSERT(array->HasFastElements()); + JSObject::EnsureCanContainHeapObjectElements(array); + + int special_length = special->length(); + if (!array->HasFastObjectElements()) { + return isolate->Throw(isolate->heap()->illegal_argument_string()); + } + + int length; + bool one_byte = special->HasOnlyOneByteChars(); + + { DisallowHeapAllocation no_gc; + FixedArray* fixed_array = FixedArray::cast(array->elements()); + if (fixed_array->length() < array_length) { + array_length = fixed_array->length(); } - SeqOneByteString* answer = SeqOneByteString::cast(object); + + if (array_length == 0) { + return isolate->heap()->empty_string(); + } else if (array_length == 1) { + Object* first = fixed_array->get(0); + if (first->IsString()) return first; + } + length = StringBuilderConcatLength( + special_length, fixed_array, array_length, &one_byte); + } + + if (length == -1) { + return isolate->Throw(isolate->heap()->illegal_argument_string()); + } + + if (one_byte) { + Handle<SeqOneByteString> answer; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, answer, + isolate->factory()->NewRawOneByteString(length)); StringBuilderConcatHelper(*special, answer->GetChars(), - fixed_array, + FixedArray::cast(array->elements()), array_length); - return answer; + return *answer; } else { - { MaybeObject* maybe_object = - isolate->heap()->AllocateRawTwoByteString(length); - if (!maybe_object->ToObject(&object)) return maybe_object; - } - SeqTwoByteString* answer = SeqTwoByteString::cast(object); + Handle<SeqTwoByteString> answer; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, answer, + isolate->factory()->NewRawTwoByteString(length)); StringBuilderConcatHelper(*special, answer->GetChars(), - fixed_array, + FixedArray::cast(array->elements()), array_length); - return answer; + return *answer; } } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_StringBuilderJoin) { + HandleScope scope(isolate); ASSERT(args.length() == 3); - CONVERT_ARG_CHECKED(JSArray, array, 0); - if (!args[1]->IsSmi()) { - isolate->context()->mark_out_of_memory(); - return Failure::OutOfMemoryException(0x16); - } - int array_length = args.smi_at(1); - CONVERT_ARG_CHECKED(String, separator, 2); + CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); + if (!args[1]->IsSmi()) return isolate->ThrowInvalidStringLength(); + CONVERT_SMI_ARG_CHECKED(array_length, 1); + CONVERT_ARG_HANDLE_CHECKED(String, separator, 2); + RUNTIME_ASSERT(array->HasFastObjectElements()); + RUNTIME_ASSERT(array_length >= 0); - if (!array->HasFastObjectElements()) { - return isolate->Throw(isolate->heap()->illegal_argument_string()); - } - FixedArray* fixed_array = FixedArray::cast(array->elements()); + Handle<FixedArray> fixed_array(FixedArray::cast(array->elements())); if (fixed_array->length() < array_length) { array_length = fixed_array->length(); } @@ -7169,54 +7295,56 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) { return isolate->heap()->empty_string(); } else if (array_length == 1) { Object* first = fixed_array->get(0); - if (first->IsString()) return first; + RUNTIME_ASSERT(first->IsString()); + return first; } int separator_length = separator->length(); + RUNTIME_ASSERT(separator_length > 0); int max_nof_separators = (String::kMaxLength + separator_length - 1) / separator_length; if (max_nof_separators < (array_length - 1)) { - isolate->context()->mark_out_of_memory(); - return Failure::OutOfMemoryException(0x17); + return isolate->ThrowInvalidStringLength(); } int length = (array_length - 1) * separator_length; for (int i = 0; i < array_length; i++) { Object* element_obj = fixed_array->get(i); - if (!element_obj->IsString()) { - // TODO(1161): handle this case. - return isolate->Throw(isolate->heap()->illegal_argument_string()); - } + RUNTIME_ASSERT(element_obj->IsString()); String* element = String::cast(element_obj); int increment = element->length(); if (increment > String::kMaxLength - length) { - isolate->context()->mark_out_of_memory(); - return Failure::OutOfMemoryException(0x18); + STATIC_ASSERT(String::kMaxLength < kMaxInt); + length = kMaxInt; // Provoke exception; + break; } length += increment; } - Object* object; - { MaybeObject* maybe_object = - isolate->heap()->AllocateRawTwoByteString(length); - if (!maybe_object->ToObject(&object)) return maybe_object; - } - SeqTwoByteString* answer = SeqTwoByteString::cast(object); + Handle<SeqTwoByteString> answer; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, answer, + isolate->factory()->NewRawTwoByteString(length)); + + DisallowHeapAllocation no_gc; uc16* sink = answer->GetChars(); #ifdef DEBUG uc16* end = sink + length; #endif + RUNTIME_ASSERT(fixed_array->get(0)->IsString()); String* first = String::cast(fixed_array->get(0)); + String* separator_raw = *separator; int first_length = first->length(); String::WriteToFlat(first, sink, 0, first_length); sink += first_length; for (int i = 1; i < array_length; i++) { ASSERT(sink + separator_length <= end); - String::WriteToFlat(separator, sink, 0, separator_length); + String::WriteToFlat(separator_raw, sink, 0, separator_length); sink += separator_length; + RUNTIME_ASSERT(fixed_array->get(i)->IsString()); String* element = String::cast(fixed_array->get(i)); int element_length = element->length(); ASSERT(sink + element_length <= end); @@ -7227,7 +7355,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) { // Use %_FastAsciiArrayJoin instead. ASSERT(!answer->IsOneByteRepresentation()); - return answer; + return *answer; } template <typename Char> @@ -7236,6 +7364,7 @@ static void JoinSparseArrayWithSeparator(FixedArray* elements, uint32_t array_length, String* separator, Vector<Char> buffer) { + DisallowHeapAllocation no_gc; int previous_separator_position = 0; int separator_length = separator->length(); int cursor = 0; @@ -7271,53 +7400,55 @@ static void JoinSparseArrayWithSeparator(FixedArray* elements, } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_SparseJoinWithSeparator) { + HandleScope scope(isolate); ASSERT(args.length() == 3); - CONVERT_ARG_CHECKED(JSArray, elements_array, 0); - RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements()); + CONVERT_ARG_HANDLE_CHECKED(JSArray, elements_array, 0); CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]); - CONVERT_ARG_CHECKED(String, separator, 2); + CONVERT_ARG_HANDLE_CHECKED(String, separator, 2); // elements_array is fast-mode JSarray of alternating positions // (increasing order) and strings. + RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements()); // array_length is length of original array (used to add separators); // separator is string to put between elements. Assumed to be non-empty. + RUNTIME_ASSERT(array_length > 0); // Find total length of join result. int string_length = 0; bool is_ascii = separator->IsOneByteRepresentation(); - int max_string_length; - if (is_ascii) { - max_string_length = SeqOneByteString::kMaxLength; - } else { - max_string_length = SeqTwoByteString::kMaxLength; - } bool overflow = false; - CONVERT_NUMBER_CHECKED(int, elements_length, - Int32, elements_array->length()); + CONVERT_NUMBER_CHECKED(int, elements_length, Int32, elements_array->length()); + RUNTIME_ASSERT(elements_length <= elements_array->elements()->length()); RUNTIME_ASSERT((elements_length & 1) == 0); // Even length. FixedArray* elements = FixedArray::cast(elements_array->elements()); for (int i = 0; i < elements_length; i += 2) { RUNTIME_ASSERT(elements->get(i)->IsNumber()); + CONVERT_NUMBER_CHECKED(uint32_t, position, Uint32, elements->get(i)); + RUNTIME_ASSERT(position < array_length); RUNTIME_ASSERT(elements->get(i + 1)->IsString()); - String* string = String::cast(elements->get(i + 1)); - int length = string->length(); - if (is_ascii && !string->IsOneByteRepresentation()) { - is_ascii = false; - max_string_length = SeqTwoByteString::kMaxLength; - } - if (length > max_string_length || - max_string_length - length < string_length) { - overflow = true; - break; + } + + { DisallowHeapAllocation no_gc; + for (int i = 0; i < elements_length; i += 2) { + String* string = String::cast(elements->get(i + 1)); + int length = string->length(); + if (is_ascii && !string->IsOneByteRepresentation()) { + is_ascii = false; + } + if (length > String::kMaxLength || + String::kMaxLength - length < string_length) { + overflow = true; + break; + } + string_length += length; } - string_length += length; } + int separator_length = separator->length(); if (!overflow && separator_length > 0) { if (array_length <= 0x7fffffffu) { int separator_count = static_cast<int>(array_length) - 1; - int remaining_length = max_string_length - string_length; + int remaining_length = String::kMaxLength - string_length; if ((remaining_length / separator_length) >= separator_count) { string_length += separator_length * (array_length - 1); } else { @@ -7332,102 +7463,98 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) { } } if (overflow) { - // Throw OutOfMemory exception for creating too large a string. - V8::FatalProcessOutOfMemory("Array join result too large."); + // Throw an exception if the resulting string is too large. See + // https://code.google.com/p/chromium/issues/detail?id=336820 + // for details. + return isolate->ThrowInvalidStringLength(); } if (is_ascii) { - MaybeObject* result_allocation = - isolate->heap()->AllocateRawOneByteString(string_length); - if (result_allocation->IsFailure()) return result_allocation; - SeqOneByteString* result_string = - SeqOneByteString::cast(result_allocation->ToObjectUnchecked()); - JoinSparseArrayWithSeparator<uint8_t>(elements, - elements_length, - array_length, - separator, - Vector<uint8_t>( - result_string->GetChars(), - string_length)); - return result_string; + Handle<SeqOneByteString> result = isolate->factory()->NewRawOneByteString( + string_length).ToHandleChecked(); + JoinSparseArrayWithSeparator<uint8_t>( + FixedArray::cast(elements_array->elements()), + elements_length, + array_length, + *separator, + Vector<uint8_t>(result->GetChars(), string_length)); + return *result; } else { - MaybeObject* result_allocation = - isolate->heap()->AllocateRawTwoByteString(string_length); - if (result_allocation->IsFailure()) return result_allocation; - SeqTwoByteString* result_string = - SeqTwoByteString::cast(result_allocation->ToObjectUnchecked()); - JoinSparseArrayWithSeparator<uc16>(elements, - elements_length, - array_length, - separator, - Vector<uc16>(result_string->GetChars(), - string_length)); - return result_string; + Handle<SeqTwoByteString> result = isolate->factory()->NewRawTwoByteString( + string_length).ToHandleChecked(); + JoinSparseArrayWithSeparator<uc16>( + FixedArray::cast(elements_array->elements()), + elements_length, + array_length, + *separator, + Vector<uc16>(result->GetChars(), string_length)); + return *result; } } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberOr) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); - return isolate->heap()->NumberFromInt32(x | y); + return *isolate->factory()->NewNumberFromInt(x | y); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberAnd) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); - return isolate->heap()->NumberFromInt32(x & y); + return *isolate->factory()->NewNumberFromInt(x & y); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberXor) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); - return isolate->heap()->NumberFromInt32(x ^ y); + return *isolate->factory()->NewNumberFromInt(x ^ y); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberShl) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); - return isolate->heap()->NumberFromInt32(x << (y & 0x1f)); + return *isolate->factory()->NewNumberFromInt(x << (y & 0x1f)); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberShr) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]); CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); - return isolate->heap()->NumberFromUint32(x >> (y & 0x1f)); + return *isolate->factory()->NewNumberFromUint(x >> (y & 0x1f)); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_NumberSar) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); - return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f)); + return *isolate->factory()->NewNumberFromInt( + ArithmeticShiftRight(x, y & 0x1f)); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) { +RUNTIME_FUNCTION(Runtime_NumberEquals) { SealHandleScope shs(isolate); ASSERT(args.length() == 2); @@ -7446,31 +7573,32 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_StringEquals) { + HandleScope handle_scope(isolate); ASSERT(args.length() == 2); - CONVERT_ARG_CHECKED(String, x, 0); - CONVERT_ARG_CHECKED(String, y, 1); + CONVERT_ARG_HANDLE_CHECKED(String, x, 0); + CONVERT_ARG_HANDLE_CHECKED(String, y, 1); - bool not_equal = !x->Equals(y); + bool not_equal = !String::Equals(x, y); // This is slightly convoluted because the value that signifies // equality is 0 and inequality is 1 so we have to negate the result // from String::Equals. ASSERT(not_equal == 0 || not_equal == 1); - STATIC_CHECK(EQUAL == 0); - STATIC_CHECK(NOT_EQUAL == 1); + STATIC_ASSERT(EQUAL == 0); + STATIC_ASSERT(NOT_EQUAL == 1); return Smi::FromInt(not_equal); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) { +RUNTIME_FUNCTION(Runtime_NumberCompare) { SealHandleScope shs(isolate); ASSERT(args.length() == 3); CONVERT_DOUBLE_ARG_CHECKED(x, 0); CONVERT_DOUBLE_ARG_CHECKED(y, 1); - if (std::isnan(x) || std::isnan(y)) return args[2]; + CONVERT_ARG_HANDLE_CHECKED(Object, uncomparable_result, 2) + if (std::isnan(x) || std::isnan(y)) return *uncomparable_result; if (x == y) return Smi::FromInt(EQUAL); if (isless(x, y)) return Smi::FromInt(LESS); return Smi::FromInt(GREATER); @@ -7479,7 +7607,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) { // Compare two Smis as if they were converted to strings and then // compared lexicographically. -RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) { +RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare) { SealHandleScope shs(isolate); ASSERT(args.length() == 2); CONVERT_SMI_ARG_CHECKED(x_value, 0); @@ -7554,27 +7682,33 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) { } -static Object* StringCharacterStreamCompare(RuntimeState* state, - String* x, - String* y) { - StringCharacterStream stream_x(x, state->string_iterator_compare_x()); - StringCharacterStream stream_y(y, state->string_iterator_compare_y()); - while (stream_x.HasMore() && stream_y.HasMore()) { - int d = stream_x.GetNext() - stream_y.GetNext(); - if (d < 0) return Smi::FromInt(LESS); - else if (d > 0) return Smi::FromInt(GREATER); +RUNTIME_FUNCTION(RuntimeHidden_StringCompare) { + HandleScope handle_scope(isolate); + ASSERT(args.length() == 2); + + CONVERT_ARG_HANDLE_CHECKED(String, x, 0); + CONVERT_ARG_HANDLE_CHECKED(String, y, 1); + + isolate->counters()->string_compare_runtime()->Increment(); + + // A few fast case tests before we flatten. + if (x.is_identical_to(y)) return Smi::FromInt(EQUAL); + if (y->length() == 0) { + if (x->length() == 0) return Smi::FromInt(EQUAL); + return Smi::FromInt(GREATER); + } else if (x->length() == 0) { + return Smi::FromInt(LESS); } - // x is (non-trivial) prefix of y: - if (stream_y.HasMore()) return Smi::FromInt(LESS); - // y is prefix of x: - return Smi::FromInt(stream_x.HasMore() ? GREATER : EQUAL); -} + int d = x->Get(0) - y->Get(0); + if (d < 0) return Smi::FromInt(LESS); + else if (d > 0) return Smi::FromInt(GREATER); + // Slow case. + x = String::Flatten(x); + y = String::Flatten(y); -static Object* FlatStringCompare(String* x, String* y) { - ASSERT(x->IsFlat()); - ASSERT(y->IsFlat()); + DisallowHeapAllocation no_gc; Object* equal_prefix_result = Smi::FromInt(EQUAL); int prefix_length = x->length(); if (y->length() < prefix_length) { @@ -7584,7 +7718,6 @@ static Object* FlatStringCompare(String* x, String* y) { equal_prefix_result = Smi::FromInt(LESS); } int r; - DisallowHeapAllocation no_gc; String::FlatContent x_content = x->GetFlatContent(); String::FlatContent y_content = y->GetFlatContent(); if (x_content.IsAscii()) { @@ -7612,82 +7745,60 @@ static Object* FlatStringCompare(String* x, String* y) { } else { result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER); } - ASSERT(result == - StringCharacterStreamCompare(x->GetIsolate()->runtime_state(), x, y)); return result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) { - SealHandleScope shs(isolate); - ASSERT(args.length() == 2); - - CONVERT_ARG_CHECKED(String, x, 0); - CONVERT_ARG_CHECKED(String, y, 1); - - isolate->counters()->string_compare_runtime()->Increment(); - - // A few fast case tests before we flatten. - if (x == y) return Smi::FromInt(EQUAL); - if (y->length() == 0) { - if (x->length() == 0) return Smi::FromInt(EQUAL); - return Smi::FromInt(GREATER); - } else if (x->length() == 0) { - return Smi::FromInt(LESS); - } - - int d = x->Get(0) - y->Get(0); - if (d < 0) return Smi::FromInt(LESS); - else if (d > 0) return Smi::FromInt(GREATER); - - Object* obj; - { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } - { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } - - return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y) - : StringCharacterStreamCompare(isolate->runtime_state(), x, y); +#define RUNTIME_UNARY_MATH(Name, name) \ +RUNTIME_FUNCTION(Runtime_Math##Name) { \ + HandleScope scope(isolate); \ + ASSERT(args.length() == 1); \ + isolate->counters()->math_##name()->Increment(); \ + CONVERT_DOUBLE_ARG_CHECKED(x, 0); \ + return *isolate->factory()->NewHeapNumber(std::name(x)); \ } +RUNTIME_UNARY_MATH(Acos, acos) +RUNTIME_UNARY_MATH(Asin, asin) +RUNTIME_UNARY_MATH(Atan, atan) +RUNTIME_UNARY_MATH(LogRT, log) +#undef RUNTIME_UNARY_MATH -RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) { - SealHandleScope shs(isolate); - ASSERT(args.length() == 1); - isolate->counters()->math_acos()->Increment(); +RUNTIME_FUNCTION(Runtime_DoubleHi) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); CONVERT_DOUBLE_ARG_CHECKED(x, 0); - return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x); + uint64_t integer = double_to_uint64(x); + integer = (integer >> 32) & 0xFFFFFFFFu; + return *isolate->factory()->NewNumber(static_cast<int32_t>(integer)); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_DoubleLo) { + HandleScope scope(isolate); ASSERT(args.length() == 1); - isolate->counters()->math_asin()->Increment(); - CONVERT_DOUBLE_ARG_CHECKED(x, 0); - return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x); + return *isolate->factory()->NewNumber( + static_cast<int32_t>(double_to_uint64(x) & 0xFFFFFFFFu)); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) { - SealHandleScope shs(isolate); - ASSERT(args.length() == 1); - isolate->counters()->math_atan()->Increment(); - - CONVERT_DOUBLE_ARG_CHECKED(x, 0); - return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x); +RUNTIME_FUNCTION(Runtime_ConstructDouble) { + HandleScope scope(isolate); + ASSERT(args.length() == 2); + CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]); + CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]); + uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo; + return *isolate->factory()->NewNumber(uint64_to_double(result)); } static const double kPiDividedBy4 = 0.78539816339744830962; -RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_MathAtan2) { + HandleScope scope(isolate); ASSERT(args.length() == 2); isolate->counters()->math_atan2()->Increment(); @@ -7703,57 +7814,37 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) { if (y < 0) multiplier *= 3; result = multiplier * kPiDividedBy4; } else { - result = atan2(x, y); + result = std::atan2(x, y); } - return isolate->heap()->AllocateHeapNumber(result); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) { - SealHandleScope shs(isolate); - ASSERT(args.length() == 1); - isolate->counters()->math_cos()->Increment(); - - CONVERT_DOUBLE_ARG_CHECKED(x, 0); - return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x); + return *isolate->factory()->NewNumber(result); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_MathExpRT) { + HandleScope scope(isolate); ASSERT(args.length() == 1); isolate->counters()->math_exp()->Increment(); CONVERT_DOUBLE_ARG_CHECKED(x, 0); lazily_initialize_fast_exp(); - return isolate->heap()->NumberFromDouble(fast_exp(x)); + return *isolate->factory()->NewNumber(fast_exp(x)); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_MathFloorRT) { + HandleScope scope(isolate); ASSERT(args.length() == 1); isolate->counters()->math_floor()->Increment(); CONVERT_DOUBLE_ARG_CHECKED(x, 0); - return isolate->heap()->NumberFromDouble(floor(x)); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) { - SealHandleScope shs(isolate); - ASSERT(args.length() == 1); - isolate->counters()->math_log()->Increment(); - - CONVERT_DOUBLE_ARG_CHECKED(x, 0); - return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x); + return *isolate->factory()->NewNumber(std::floor(x)); } // Slow version of Math.pow. We check for fast paths for special cases. -// Used if SSE2/VFP3 is not available. -RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) { - SealHandleScope shs(isolate); +// Used if VFP3 is not available. +RUNTIME_FUNCTION(RuntimeHidden_MathPowSlow) { + HandleScope scope(isolate); ASSERT(args.length() == 2); isolate->counters()->math_pow()->Increment(); @@ -7763,20 +7854,20 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) { // custom powi() function than the generic pow(). if (args[1]->IsSmi()) { int y = args.smi_at(1); - return isolate->heap()->NumberFromDouble(power_double_int(x, y)); + return *isolate->factory()->NewNumber(power_double_int(x, y)); } CONVERT_DOUBLE_ARG_CHECKED(y, 1); double result = power_helper(x, y); if (std::isnan(result)) return isolate->heap()->nan_value(); - return isolate->heap()->AllocateHeapNumber(result); + return *isolate->factory()->NewNumber(result); } // Fast version of Math.pow if we know that y is not an integer and y is not // -0.5 or 0.5. Used as slow case from full codegen. -RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_MathPow) { + HandleScope scope(isolate); ASSERT(args.length() == 2); isolate->counters()->math_pow()->Increment(); @@ -7787,23 +7878,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) { } else { double result = power_double_double(x, y); if (std::isnan(result)) return isolate->heap()->nan_value(); - return isolate->heap()->AllocateHeapNumber(result); + return *isolate->factory()->NewNumber(result); } } -RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_RoundNumber) { + HandleScope scope(isolate); ASSERT(args.length() == 1); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(input, 0); isolate->counters()->math_round()->Increment(); - if (!args[0]->IsHeapNumber()) { - // Must be smi. Return the argument unchanged for all the other types - // to make fuzz-natives test happy. - return args[0]; + if (!input->IsHeapNumber()) { + ASSERT(input->IsSmi()); + return *input; } - HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]); + Handle<HeapNumber> number = Handle<HeapNumber>::cast(input); double value = number->value(); int exponent = number->get_exponent(); @@ -7825,58 +7916,50 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) { // If the magnitude is big enough, there's no place for fraction part. If we // try to add 0.5 to this number, 1.0 will be added instead. if (exponent >= 52) { - return number; + return *number; } if (sign && value >= -0.5) return isolate->heap()->minus_zero_value(); // Do not call NumberFromDouble() to avoid extra checks. - return isolate->heap()->AllocateHeapNumber(floor(value + 0.5)); + return *isolate->factory()->NewNumber(std::floor(value + 0.5)); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) { - SealHandleScope shs(isolate); - ASSERT(args.length() == 1); - isolate->counters()->math_sin()->Increment(); - - CONVERT_DOUBLE_ARG_CHECKED(x, 0); - return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_MathSqrtRT) { + HandleScope scope(isolate); ASSERT(args.length() == 1); isolate->counters()->math_sqrt()->Increment(); CONVERT_DOUBLE_ARG_CHECKED(x, 0); - return isolate->heap()->AllocateHeapNumber(fast_sqrt(x)); + return *isolate->factory()->NewNumber(fast_sqrt(x)); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_MathFround) { + HandleScope scope(isolate); ASSERT(args.length() == 1); - isolate->counters()->math_tan()->Increment(); CONVERT_DOUBLE_ARG_CHECKED(x, 0); - return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x); + float xf = static_cast<float>(x); + return *isolate->factory()->NewNumber(xf); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) { +RUNTIME_FUNCTION(Runtime_DateMakeDay) { SealHandleScope shs(isolate); ASSERT(args.length() == 2); CONVERT_SMI_ARG_CHECKED(year, 0); CONVERT_SMI_ARG_CHECKED(month, 1); - return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month)); + int days = isolate->date_cache()->DaysFromYearMonth(year, month); + RUNTIME_ASSERT(Smi::IsValid(days)); + return Smi::FromInt(days); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) { +RUNTIME_FUNCTION(Runtime_DateSetValue) { HandleScope scope(isolate); ASSERT(args.length() == 3); @@ -7886,40 +7969,38 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) { DateCache* date_cache = isolate->date_cache(); - Object* value = NULL; + Handle<Object> value;; bool is_value_nan = false; if (std::isnan(time)) { - value = isolate->heap()->nan_value(); + value = isolate->factory()->nan_value(); is_value_nan = true; } else if (!is_utc && (time < -DateCache::kMaxTimeBeforeUTCInMs || time > DateCache::kMaxTimeBeforeUTCInMs)) { - value = isolate->heap()->nan_value(); + value = isolate->factory()->nan_value(); is_value_nan = true; } else { time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time)); if (time < -DateCache::kMaxTimeInMs || time > DateCache::kMaxTimeInMs) { - value = isolate->heap()->nan_value(); + value = isolate->factory()->nan_value(); is_value_nan = true; } else { - MaybeObject* maybe_result = - isolate->heap()->AllocateHeapNumber(DoubleToInteger(time)); - if (!maybe_result->ToObject(&value)) return maybe_result; + value = isolate->factory()->NewNumber(DoubleToInteger(time)); } } - date->SetValue(value, is_value_nan); - return value; + date->SetValue(*value, is_value_nan); + return *value; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) { +RUNTIME_FUNCTION(RuntimeHidden_NewSloppyArguments) { HandleScope scope(isolate); ASSERT(args.length() == 3); - Handle<JSFunction> callee = args.at<JSFunction>(0); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0); Object** parameters = reinterpret_cast<Object**>(args[1]); - const int argument_count = Smi::cast(args[2])->value(); + CONVERT_SMI_ARG_CHECKED(argument_count, 2); Handle<JSObject> result = isolate->factory()->NewArgumentsObject(callee, argument_count); @@ -7931,13 +8012,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) { Handle<FixedArray> parameter_map = isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED); parameter_map->set_map( - isolate->heap()->non_strict_arguments_elements_map()); + isolate->heap()->sloppy_arguments_elements_map()); - Handle<Map> old_map(result->map()); - Handle<Map> new_map = isolate->factory()->CopyMap(old_map); - new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS); + Handle<Map> map = Map::Copy(handle(result->map())); + map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS); - result->set_map(*new_map); + result->set_map(*map); result->set_elements(*parameter_map); // Store the context and the arguments array at the beginning of the @@ -8008,54 +8088,42 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_NewStrictArguments) { + HandleScope scope(isolate); ASSERT(args.length() == 3); - - JSFunction* callee = JSFunction::cast(args[0]); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0) Object** parameters = reinterpret_cast<Object**>(args[1]); - const int length = args.smi_at(2); + CONVERT_SMI_ARG_CHECKED(length, 2); - Object* result; - { MaybeObject* maybe_result = - isolate->heap()->AllocateArgumentsObject(callee, length); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - // Allocate the elements if needed. - if (length > 0) { - // Allocate the fixed array. - FixedArray* array; - { MaybeObject* maybe_obj = - isolate->heap()->AllocateUninitializedFixedArray(length); - if (!maybe_obj->To(&array)) return maybe_obj; - } + Handle<JSObject> result = + isolate->factory()->NewArgumentsObject(callee, length); + if (length > 0) { + Handle<FixedArray> array = + isolate->factory()->NewUninitializedFixedArray(length); DisallowHeapAllocation no_gc; WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc); for (int i = 0; i < length; i++) { array->set(i, *--parameters, mode); } - JSObject::cast(result)->set_elements(array); + result->set_elements(*array); } - return result; + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosureFromStubFailure) { +RUNTIME_FUNCTION(RuntimeHidden_NewClosureFromStubFailure) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0); Handle<Context> context(isolate->context()); PretenureFlag pretenure_flag = NOT_TENURED; - Handle<JSFunction> result = - isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, - context, - pretenure_flag); - return *result; + return *isolate->factory()->NewFunctionFromSharedFunctionInfo( + shared, context, pretenure_flag); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) { +RUNTIME_FUNCTION(RuntimeHidden_NewClosure) { HandleScope scope(isolate); ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); @@ -8065,11 +8133,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) { // The caller ensures that we pretenure closures that are assigned // directly to properties. PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED; - Handle<JSFunction> result = - isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, - context, - pretenure_flag); - return *result; + return *isolate->factory()->NewFunctionFromSharedFunctionInfo( + shared, context, pretenure_flag); } @@ -8088,23 +8153,22 @@ static SmartArrayPointer<Handle<Object> > GetCallerArguments( if (functions.length() > 1) { int inlined_jsframe_index = functions.length() - 1; JSFunction* inlined_function = functions[inlined_jsframe_index]; - Vector<SlotRef> args_slots = - SlotRef::ComputeSlotMappingForArguments( - frame, - inlined_jsframe_index, - inlined_function->shared()->formal_parameter_count()); + SlotRefValueBuilder slot_refs( + frame, + inlined_jsframe_index, + inlined_function->shared()->formal_parameter_count()); - int args_count = args_slots.length(); + int args_count = slot_refs.args_length(); *total_argc = prefix_argc + args_count; SmartArrayPointer<Handle<Object> > param_data( NewArray<Handle<Object> >(*total_argc)); + slot_refs.Prepare(isolate); for (int i = 0; i < args_count; i++) { - Handle<Object> val = args_slots[i].GetValue(isolate); + Handle<Object> val = slot_refs.GetNext(isolate, 0); param_data[prefix_argc + i] = val; } - - args_slots.Dispose(); + slot_refs.Finish(isolate); return param_data; } else { @@ -8124,12 +8188,13 @@ static SmartArrayPointer<Handle<Object> > GetCallerArguments( } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) { +RUNTIME_FUNCTION(Runtime_FunctionBindArguments) { HandleScope scope(isolate); ASSERT(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0); - RUNTIME_ASSERT(args[3]->IsNumber()); - Handle<Object> bindee = args.at<Object>(1); + CONVERT_ARG_HANDLE_CHECKED(Object, bindee, 1); + CONVERT_ARG_HANDLE_CHECKED(Object, this_object, 2); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(new_length, 3); // TODO(lrn): Create bound function in C++ code from premade shared info. bound_function->shared()->set_bound(true); @@ -8139,10 +8204,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) { GetCallerArguments(isolate, 0, &argc); // Don't count the this-arg. if (argc > 0) { - ASSERT(*arguments[0] == args[2]); + RUNTIME_ASSERT(arguments[0].is_identical_to(this_object)); argc--; } else { - ASSERT(args[2]->IsUndefined()); + RUNTIME_ASSERT(this_object->IsUndefined()); } // Initialize array of bindings (function, this, and any existing arguments // if the function was already bound). @@ -8151,6 +8216,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) { if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) { Handle<FixedArray> old_bindings( JSFunction::cast(*bindee)->function_bindings()); + RUNTIME_ASSERT(old_bindings->length() > JSFunction::kBoundFunctionIndex); new_bindings = isolate->factory()->NewFixedArray(old_bindings->length() + argc); bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex), @@ -8163,7 +8229,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) { int array_size = JSFunction::kBoundArgumentsStartIndex + argc; new_bindings = isolate->factory()->NewFixedArray(array_size); new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee); - new_bindings->set(JSFunction::kBoundThisIndex, args[2]); + new_bindings->set(JSFunction::kBoundThisIndex, *this_object); i = 2; } // Copy arguments, skipping the first which is "this_arg". @@ -8174,17 +8240,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) { isolate->heap()->fixed_cow_array_map()); bound_function->set_function_bindings(*new_bindings); - // Update length. + // Update length. Have to remove the prototype first so that map migration + // is happy about the number of fields. + RUNTIME_ASSERT(bound_function->RemovePrototype()); + Handle<Map> bound_function_map( + isolate->native_context()->bound_function_map()); + JSObject::MigrateToMap(bound_function, bound_function_map); Handle<String> length_string = isolate->factory()->length_string(); - Handle<Object> new_length(args.at<Object>(3)); PropertyAttributes attr = static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY); - ForceSetProperty(bound_function, length_string, new_length, attr); + RETURN_FAILURE_ON_EXCEPTION( + isolate, + JSObject::SetOwnPropertyIgnoreAttributes(bound_function, length_string, + new_length, attr)); return *bound_function; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) { +RUNTIME_FUNCTION(Runtime_BoundFunctionGetBindings) { HandleScope handles(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0); @@ -8192,7 +8265,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) { Handle<JSFunction> function = Handle<JSFunction>::cast(callable); if (function->shared()->bound()) { Handle<FixedArray> bindings(function->function_bindings()); - ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map()); + RUNTIME_ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map()); return *isolate->factory()->NewJSArrayWithElements(bindings); } } @@ -8200,7 +8273,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) { +RUNTIME_FUNCTION(Runtime_NewObjectFromBound) { HandleScope scope(isolate); ASSERT(args.length() == 1); // First argument is a function to use as a constructor. @@ -8227,32 +8300,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) { } if (!bound_function->IsJSFunction()) { - bool exception_thrown; - bound_function = Execution::TryGetConstructorDelegate(isolate, - bound_function, - &exception_thrown); - if (exception_thrown) return Failure::Exception(); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, bound_function, + Execution::TryGetConstructorDelegate(isolate, bound_function)); } ASSERT(bound_function->IsJSFunction()); - bool exception = false; - Handle<Object> result = + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, Execution::New(Handle<JSFunction>::cast(bound_function), - total_argc, *param_data, &exception); - if (exception) { - return Failure::Exception(); - } - ASSERT(!result.is_null()); + total_argc, param_data.get())); return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) { - HandleScope scope(isolate); - ASSERT(args.length() == 1); - - Handle<Object> constructor = args.at<Object>(0); - +static Object* Runtime_NewObjectHelper(Isolate* isolate, + Handle<Object> constructor, + Handle<AllocationSite> site) { // If the constructor isn't a proper function we throw a type error. if (!constructor->IsJSFunction()) { Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); @@ -8272,13 +8337,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) { return isolate->Throw(*type_error); } -#ifdef ENABLE_DEBUGGER_SUPPORT Debug* debug = isolate->debug(); // Handle stepping into constructors if step into is active. if (debug->StepInActive()) { debug->HandleStepIn(function, Handle<Object>::null(), 0, true); } -#endif if (function->has_initial_map()) { if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) { @@ -8299,20 +8362,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) { // The function should be compiled for the optimization hints to be // available. - JSFunction::EnsureCompiled(function, CLEAR_EXCEPTION); + Compiler::EnsureCompiled(function, CLEAR_EXCEPTION); - Handle<SharedFunctionInfo> shared(function->shared(), isolate); - if (!function->has_initial_map() && - shared->IsInobjectSlackTrackingInProgress()) { - // The tracking is already in progress for another function. We can only - // track one initial_map at a time, so we force the completion before the - // function is called as a constructor for the first time. - shared->CompleteInobjectSlackTracking(); + Handle<JSObject> result; + if (site.is_null()) { + result = isolate->factory()->NewJSObject(function); + } else { + result = isolate->factory()->NewJSObjectWithMemento(function, site); } - Handle<JSObject> result = isolate->factory()->NewJSObject(function); - RETURN_IF_EMPTY_HANDLE(isolate, result); - isolate->counters()->constructed_objects()->Increment(); isolate->counters()->constructed_objects_runtime()->Increment(); @@ -8320,53 +8378,88 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) { +RUNTIME_FUNCTION(RuntimeHidden_NewObject) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 0); + return Runtime_NewObjectHelper(isolate, + constructor, + Handle<AllocationSite>::null()); +} + + +RUNTIME_FUNCTION(RuntimeHidden_NewObjectWithAllocationSite) { + HandleScope scope(isolate); + ASSERT(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 1); + CONVERT_ARG_HANDLE_CHECKED(Object, feedback, 0); + Handle<AllocationSite> site; + if (feedback->IsAllocationSite()) { + // The feedback can be an AllocationSite or undefined. + site = Handle<AllocationSite>::cast(feedback); + } + return Runtime_NewObjectHelper(isolate, constructor, site); +} + + +RUNTIME_FUNCTION(RuntimeHidden_FinalizeInstanceSize) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); - function->shared()->CompleteInobjectSlackTracking(); + function->CompleteInobjectSlackTracking(); return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) { +RUNTIME_FUNCTION(RuntimeHidden_CompileUnoptimized) { HandleScope scope(isolate); ASSERT(args.length() == 1); - - Handle<JSFunction> function = args.at<JSFunction>(0); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); #ifdef DEBUG if (FLAG_trace_lazy && !function->shared()->is_compiled()) { - PrintF("[lazy: "); + PrintF("[unoptimized: "); function->PrintName(); PrintF("]\n"); } #endif // Compile the target function. - ASSERT(!function->is_compiled()); - if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) { - return Failure::Exception(); - } + ASSERT(function->shared()->allows_lazy_compilation()); + + Handle<Code> code; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, code, + Compiler::GetUnoptimizedCode(function)); + function->ReplaceCode(*code); // All done. Return the compiled code. ASSERT(function->is_compiled()); - return function->code(); + ASSERT(function->code()->kind() == Code::FUNCTION || + (FLAG_always_opt && + function->code()->kind() == Code::OPTIMIZED_FUNCTION)); + return *code; } -bool AllowOptimization(Isolate* isolate, Handle<JSFunction> function) { - // If the function is not compiled ignore the lazy - // recompilation. This can happen if the debugger is activated and - // the function is returned to the not compiled state. - if (!function->shared()->is_compiled()) return false; - - // If the function is not optimizable or debugger is active continue using the - // code from the full compiler. - if (!isolate->use_crankshaft() || - function->shared()->optimization_disabled() || - isolate->DebuggerHasBreakPoints()) { +RUNTIME_FUNCTION(RuntimeHidden_CompileOptimized) { + HandleScope scope(isolate); + ASSERT(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); + CONVERT_BOOLEAN_ARG_CHECKED(concurrent, 1); + + Handle<Code> unoptimized(function->shared()->code()); + if (!function->shared()->is_compiled()) { + // If the function is not compiled, do not optimize. + // This can happen if the debugger is activated and + // the function is returned to the not compiled state. + // TODO(yangguo): reconsider this. + function->ReplaceCode(function->shared()->code()); + } else if (!isolate->use_crankshaft() || + function->shared()->optimization_disabled() || + isolate->DebuggerHasBreakPoints()) { + // If the function is not optimizable or debugger is active continue + // using the code from the full compiler. if (FLAG_trace_opt) { PrintF("[failed to optimize "); function->PrintName(); @@ -8374,52 +8467,26 @@ bool AllowOptimization(Isolate* isolate, Handle<JSFunction> function) { function->shared()->optimization_disabled() ? "F" : "T", isolate->DebuggerHasBreakPoints() ? "T" : "F"); } - return false; + function->ReplaceCode(*unoptimized); + } else { + Compiler::ConcurrencyMode mode = concurrent ? Compiler::CONCURRENT + : Compiler::NOT_CONCURRENT; + Handle<Code> code; + if (Compiler::GetOptimizedCode( + function, unoptimized, mode).ToHandle(&code)) { + function->ReplaceCode(*code); + } else { + function->ReplaceCode(*unoptimized); + } } - return true; -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) { - HandleScope scope(isolate); - ASSERT(args.length() == 1); - Handle<JSFunction> function = args.at<JSFunction>(0); - if (!AllowOptimization(isolate, function)) { - function->ReplaceCode(function->shared()->code()); - return function->code(); - } - function->shared()->code()->set_profiler_ticks(0); - if (JSFunction::CompileOptimized(function, CLEAR_EXCEPTION)) { - return function->code(); - } - if (FLAG_trace_opt) { - PrintF("[failed to optimize "); - function->PrintName(); - PrintF(": optimized compilation failed]\n"); - } - function->ReplaceCode(function->shared()->code()); + ASSERT(function->code()->kind() == Code::FUNCTION || + function->code()->kind() == Code::OPTIMIZED_FUNCTION || + function->IsInOptimizationQueue()); return function->code(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ConcurrentRecompile) { - HandleScope handle_scope(isolate); - ASSERT(args.length() == 1); - CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); - if (!AllowOptimization(isolate, function)) { - function->ReplaceCode(function->shared()->code()); - return isolate->heap()->undefined_value(); - } - function->shared()->code()->set_profiler_ticks(0); - ASSERT(isolate->concurrent_recompilation_enabled()); - if (!Compiler::RecompileConcurrent(function)) { - function->ReplaceCode(function->shared()->code()); - } - return isolate->heap()->undefined_value(); -} - - class ActivationsFinder : public ThreadVisitor { public: Code* code_; @@ -8443,7 +8510,7 @@ class ActivationsFinder : public ThreadVisitor { }; -RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyStubFailure) { +RUNTIME_FUNCTION(RuntimeHidden_NotifyStubFailure) { HandleScope scope(isolate); ASSERT(args.length() == 0); Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); @@ -8453,12 +8520,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyStubFailure) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) { +RUNTIME_FUNCTION(RuntimeHidden_NotifyDeoptimized) { HandleScope scope(isolate); ASSERT(args.length() == 1); - RUNTIME_ASSERT(args[0]->IsSmi()); + CONVERT_SMI_ARG_CHECKED(type_arg, 0); Deoptimizer::BailoutType type = - static_cast<Deoptimizer::BailoutType>(args.smi_at(0)); + static_cast<Deoptimizer::BailoutType>(type_arg); Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); ASSERT(AllowHeapAllocation::IsAllowed()); @@ -8496,6 +8563,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) { PrintF("]\n"); } function->ReplaceCode(function->shared()->code()); + // Evict optimized code for this function from the cache so that it + // doesn't get used for new closures. + function->shared()->EvictFromOptimizedCodeMap(*optimized_code, + "notify deoptimized"); } } else { // TODO(titzer): we should probably do DeoptimizeCodeList(code) @@ -8503,16 +8574,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) { // If there is an index by shared function info, all the better. Deoptimizer::DeoptimizeFunction(*function); } - // Evict optimized code for this function from the cache so that it doesn't - // get used for new closures. - function->shared()->EvictFromOptimizedCodeMap(*optimized_code, - "notify deoptimized"); return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) { +RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); @@ -8524,21 +8591,22 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearFunctionTypeFeedback) { +RUNTIME_FUNCTION(Runtime_ClearFunctionTypeFeedback) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); + function->shared()->ClearTypeFeedbackInfo(); Code* unoptimized = function->shared()->code(); if (unoptimized->kind() == Code::FUNCTION) { unoptimized->ClearInlineCaches(); - unoptimized->ClearTypeFeedbackCells(isolate->heap()); } return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) { +RUNTIME_FUNCTION(Runtime_RunningInSimulator) { SealHandleScope shs(isolate); + ASSERT(args.length() == 0); #if defined(USE_SIMULATOR) return isolate->heap()->true_value(); #else @@ -8547,20 +8615,26 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConcurrentRecompilationSupported) { - HandleScope scope(isolate); - return isolate->concurrent_recompilation_enabled() - ? isolate->heap()->true_value() : isolate->heap()->false_value(); +RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) { + SealHandleScope shs(isolate); + ASSERT(args.length() == 0); + return isolate->heap()->ToBoolean( + isolate->concurrent_recompilation_enabled()); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) { +RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) { HandleScope scope(isolate); RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); - if (!function->IsOptimizable()) return isolate->heap()->undefined_value(); - function->MarkForLazyRecompilation(); + if (!function->IsOptimizable() && + !function->IsMarkedForConcurrentOptimization() && + !function->IsInOptimizationQueue()) { + return isolate->heap()->undefined_value(); + } + + function->MarkForOptimization(); Code* unoptimized = function->shared()->code(); if (args.length() == 2 && @@ -8570,12 +8644,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) { // Start patching from the currently patched loop nesting level. int current_level = unoptimized->allow_osr_at_loop_nesting_level(); ASSERT(BackEdgeTable::Verify(isolate, unoptimized, current_level)); - for (int i = current_level + 1; i <= Code::kMaxLoopNestingMarker; i++) { - unoptimized->set_allow_osr_at_loop_nesting_level(i); - isolate->runtime_profiler()->AttemptOnStackReplacement(*function); + if (FLAG_use_osr) { + for (int i = current_level + 1; i <= Code::kMaxLoopNestingMarker; i++) { + unoptimized->set_allow_osr_at_loop_nesting_level(i); + isolate->runtime_profiler()->AttemptOnStackReplacement(*function); + } } - } else if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("concurrent"))) { - function->MarkForConcurrentRecompilation(); + } else if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("concurrent")) && + isolate->concurrent_recompilation_enabled()) { + function->MarkForConcurrentOptimization(); } } @@ -8583,17 +8660,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NeverOptimizeFunction) { +RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSFunction, function, 0); - ASSERT(!function->IsOptimized()); function->shared()->set_optimization_disabled(true); return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) { +RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) { HandleScope scope(isolate); RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); if (!isolate->use_crankshaft()) { @@ -8609,7 +8685,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) { CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); if (isolate->concurrent_recompilation_enabled() && sync_with_compiler_thread) { - while (function->IsInRecompileQueue()) { + while (function->IsInOptimizationQueue()) { isolate->optimizing_compiler_thread()->InstallOptimizedFunctions(); OS::Sleep(50); } @@ -8628,14 +8704,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_UnblockConcurrentRecompilation) { +RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) { + ASSERT(args.length() == 0); RUNTIME_ASSERT(FLAG_block_concurrent_recompilation); + RUNTIME_ASSERT(isolate->concurrent_recompilation_enabled()); isolate->optimizing_compiler_thread()->Unblock(); return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) { +RUNTIME_FUNCTION(Runtime_GetOptimizationCount) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); @@ -8645,9 +8723,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) { static bool IsSuitableForOnStackReplacement(Isolate* isolate, Handle<JSFunction> function, - Handle<Code> unoptimized) { + Handle<Code> current_code) { // Keep track of whether we've succeeded in optimizing. - if (!isolate->use_crankshaft() || !unoptimized->optimizable()) return false; + if (!isolate->use_crankshaft() || !current_code->optimizable()) return false; // If we are trying to do OSR when there are already optimized // activations of the function, it means (a) the function is directly or // indirectly recursive and (b) an optimized invocation has been @@ -8662,76 +8740,88 @@ static bool IsSuitableForOnStackReplacement(Isolate* isolate, } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) { +RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) { HandleScope scope(isolate); - ASSERT(args.length() == 2); + ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); - CONVERT_NUMBER_CHECKED(uint32_t, pc_offset, Uint32, args[1]); - Handle<Code> unoptimized(function->shared()->code(), isolate); + Handle<Code> caller_code(function->shared()->code()); -#ifdef DEBUG + // We're not prepared to handle a function with arguments object. + ASSERT(!function->shared()->uses_arguments()); + + RUNTIME_ASSERT(FLAG_use_osr); + + // Passing the PC in the javascript frame from the caller directly is + // not GC safe, so we walk the stack to get it. JavaScriptFrameIterator it(isolate); JavaScriptFrame* frame = it.frame(); - ASSERT_EQ(frame->function(), *function); - ASSERT_EQ(frame->LookupCode(), *unoptimized); - ASSERT(unoptimized->contains(frame->pc())); + if (!caller_code->contains(frame->pc())) { + // Code on the stack may not be the code object referenced by the shared + // function info. It may have been replaced to include deoptimization data. + caller_code = Handle<Code>(frame->LookupCode()); + } + + uint32_t pc_offset = static_cast<uint32_t>( + frame->pc() - caller_code->instruction_start()); - ASSERT(pc_offset == - static_cast<uint32_t>(frame->pc() - unoptimized->instruction_start())); +#ifdef DEBUG + ASSERT_EQ(frame->function(), *function); + ASSERT_EQ(frame->LookupCode(), *caller_code); + ASSERT(caller_code->contains(frame->pc())); #endif // DEBUG - // We're not prepared to handle a function with arguments object. - ASSERT(!function->shared()->uses_arguments()); + BailoutId ast_id = caller_code->TranslatePcOffsetToAstId(pc_offset); + ASSERT(!ast_id.IsNone()); + + Compiler::ConcurrencyMode mode = + isolate->concurrent_osr_enabled() && + (function->shared()->ast_node_count() > 512) ? Compiler::CONCURRENT + : Compiler::NOT_CONCURRENT; Handle<Code> result = Handle<Code>::null(); - BailoutId ast_id = BailoutId::None(); - if (isolate->concurrent_osr_enabled()) { - if (isolate->optimizing_compiler_thread()-> - IsQueuedForOSR(function, pc_offset)) { - // Still waiting for the optimizing compiler thread to finish. Carry on. + OptimizedCompileJob* job = NULL; + if (mode == Compiler::CONCURRENT) { + // Gate the OSR entry with a stack check. + BackEdgeTable::AddStackCheck(caller_code, pc_offset); + // Poll already queued compilation jobs. + OptimizingCompilerThread* thread = isolate->optimizing_compiler_thread(); + if (thread->IsQueuedForOSR(function, ast_id)) { if (FLAG_trace_osr) { - PrintF("[COSR - polling recompile tasks for "); + PrintF("[OSR - Still waiting for queued: "); function->PrintName(); - PrintF("]\n"); + PrintF(" at AST id %d]\n", ast_id.ToInt()); } return NULL; } - RecompileJob* job = isolate->optimizing_compiler_thread()-> - FindReadyOSRCandidate(function, pc_offset); + job = thread->FindReadyOSRCandidate(function, ast_id); + } - if (job == NULL) { - if (IsSuitableForOnStackReplacement(isolate, function, unoptimized) && - Compiler::RecompileConcurrent(function, pc_offset)) { - if (function->IsMarkedForLazyRecompilation() || - function->IsMarkedForConcurrentRecompilation()) { - // Prevent regular recompilation if we queue this for OSR. - // TODO(yangguo): remove this as soon as OSR becomes one-shot. - function->ReplaceCode(*unoptimized); - } - return NULL; - } - // Fall through to the end in case of failure. - } else { - // TODO(titzer): don't install the OSR code into the function. - ast_id = job->info()->osr_ast_id(); - result = Compiler::InstallOptimizedCode(job); + if (job != NULL) { + if (FLAG_trace_osr) { + PrintF("[OSR - Found ready: "); + function->PrintName(); + PrintF(" at AST id %d]\n", ast_id.ToInt()); } - } else if (IsSuitableForOnStackReplacement(isolate, function, unoptimized)) { - ast_id = unoptimized->TranslatePcOffsetToAstId(pc_offset); - ASSERT(!ast_id.IsNone()); + result = Compiler::GetConcurrentlyOptimizedCode(job); + } else if (IsSuitableForOnStackReplacement(isolate, function, caller_code)) { if (FLAG_trace_osr) { - PrintF("[OSR - replacing at AST id %d in ", ast_id.ToInt()); + PrintF("[OSR - Compiling: "); function->PrintName(); - PrintF("]\n"); + PrintF(" at AST id %d]\n", ast_id.ToInt()); + } + MaybeHandle<Code> maybe_result = Compiler::GetOptimizedCode( + function, caller_code, mode, ast_id); + if (maybe_result.ToHandle(&result) && + result.is_identical_to(isolate->builtins()->InOptimizationQueue())) { + // Optimization is queued. Return to check later. + return NULL; } - // Attempt OSR compilation. - result = JSFunction::CompileOsr(function, ast_id, CLEAR_EXCEPTION); } // Revert the patched back edge table, regardless of whether OSR succeeds. - BackEdgeTable::Revert(isolate, *unoptimized); + BackEdgeTable::Revert(isolate, *caller_code); // Check whether we ended up with usable optimized code. if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) { @@ -8741,58 +8831,72 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) { if (data->OsrPcOffset()->value() >= 0) { ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id); if (FLAG_trace_osr) { - PrintF("[OSR - entry at AST id %d, offset %d in optimized code]\n", + PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n", ast_id.ToInt(), data->OsrPcOffset()->value()); } // TODO(titzer): this is a massive hack to make the deopt counts // match. Fix heuristics for reenabling optimizations! function->shared()->increment_deopt_count(); + + // TODO(titzer): Do not install code into the function. + function->ReplaceCode(*result); return *result; } } + // Failed. if (FLAG_trace_osr) { - PrintF("[OSR - optimization failed for "); + PrintF("[OSR - Failed: "); function->PrintName(); - PrintF("]\n"); + PrintF(" at AST id %d]\n", ast_id.ToInt()); } - if (function->IsMarkedForLazyRecompilation() || - function->IsMarkedForConcurrentRecompilation()) { + if (!function->IsOptimized()) { function->ReplaceCode(function->shared()->code()); } return NULL; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAllocationTimeout) { +RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) { SealHandleScope shs(isolate); - ASSERT(args.length() == 2); + ASSERT(args.length() == 2 || args.length() == 3); #ifdef DEBUG CONVERT_SMI_ARG_CHECKED(interval, 0); CONVERT_SMI_ARG_CHECKED(timeout, 1); isolate->heap()->set_allocation_timeout(timeout); FLAG_gc_interval = interval; + if (args.length() == 3) { + // Enable/disable inline allocation if requested. + CONVERT_BOOLEAN_ARG_CHECKED(inline_allocation, 2); + if (inline_allocation) { + isolate->heap()->EnableInlineAllocation(); + } else { + isolate->heap()->DisableInlineAllocation(); + } + } #endif return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) { +RUNTIME_FUNCTION(Runtime_CheckIsBootstrapping) { SealHandleScope shs(isolate); + ASSERT(args.length() == 0); RUNTIME_ASSERT(isolate->bootstrapper()->IsActive()); return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetRootNaN) { +RUNTIME_FUNCTION(Runtime_GetRootNaN) { SealHandleScope shs(isolate); + ASSERT(args.length() == 0); RUNTIME_ASSERT(isolate->bootstrapper()->IsActive()); return isolate->heap()->nan_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) { +RUNTIME_FUNCTION(Runtime_Call) { HandleScope scope(isolate); ASSERT(args.length() >= 2); int argc = args.length() - 2; @@ -8811,33 +8915,32 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) { } for (int i = 0; i < argc; ++i) { - MaybeObject* maybe = args[1 + i]; - Object* object; - if (!maybe->To<Object>(&object)) return maybe; - argv[i] = Handle<Object>(object, isolate); + argv[i] = Handle<Object>(args[1 + i], isolate); } - bool threw; Handle<JSReceiver> hfun(fun); Handle<Object> hreceiver(receiver, isolate); - Handle<Object> result = Execution::Call( - isolate, hfun, hreceiver, argc, argv, &threw, true); - - if (threw) return Failure::Exception(); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + Execution::Call(isolate, hfun, hreceiver, argc, argv, true)); return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) { +RUNTIME_FUNCTION(Runtime_Apply) { HandleScope scope(isolate); ASSERT(args.length() == 5); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0); - Handle<Object> receiver = args.at<Object>(1); + CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1); CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2); CONVERT_SMI_ARG_CHECKED(offset, 3); CONVERT_SMI_ARG_CHECKED(argc, 4); RUNTIME_ASSERT(offset >= 0); - RUNTIME_ASSERT(argc >= 0); + // Loose upper bound to allow fuzzing. We'll most likely run out of + // stack space before hitting this limit. + static int kMaxArgc = 1000000; + RUNTIME_ASSERT(argc >= 0 && argc <= kMaxArgc); // If there are too many arguments, allocate argv via malloc. const int argv_small_size = 10; @@ -8851,174 +8954,152 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) { } for (int i = 0; i < argc; ++i) { - argv[i] = Object::GetElement(isolate, arguments, offset + i); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, argv[i], + Object::GetElement(isolate, arguments, offset + i)); } - bool threw; - Handle<Object> result = Execution::Call( - isolate, fun, receiver, argc, argv, &threw, true); - - if (threw) return Failure::Exception(); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + Execution::Call(isolate, fun, receiver, argc, argv, true)); return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) { +RUNTIME_FUNCTION(Runtime_GetFunctionDelegate) { HandleScope scope(isolate); ASSERT(args.length() == 1); - RUNTIME_ASSERT(!args[0]->IsJSFunction()); - return *Execution::GetFunctionDelegate(isolate, args.at<Object>(0)); + CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); + RUNTIME_ASSERT(!object->IsJSFunction()); + return *Execution::GetFunctionDelegate(isolate, object); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) { +RUNTIME_FUNCTION(Runtime_GetConstructorDelegate) { HandleScope scope(isolate); ASSERT(args.length() == 1); - RUNTIME_ASSERT(!args[0]->IsJSFunction()); - return *Execution::GetConstructorDelegate(isolate, args.at<Object>(0)); + CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); + RUNTIME_ASSERT(!object->IsJSFunction()); + return *Execution::GetConstructorDelegate(isolate, object); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NewGlobalContext) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_NewGlobalContext) { + HandleScope scope(isolate); ASSERT(args.length() == 2); - CONVERT_ARG_CHECKED(JSFunction, function, 0); - CONVERT_ARG_CHECKED(ScopeInfo, scope_info, 1); - Context* result; - MaybeObject* maybe_result = - isolate->heap()->AllocateGlobalContext(function, scope_info); - if (!maybe_result->To(&result)) return maybe_result; + CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); + CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1); + Handle<Context> result = + isolate->factory()->NewGlobalContext(function, scope_info); ASSERT(function->context() == isolate->context()); ASSERT(function->context()->global_object() == result->global_object()); - isolate->set_context(result); - result->global_object()->set_global_context(result); - - return result; // non-failure + result->global_object()->set_global_context(*result); + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_NewFunctionContext) { + HandleScope scope(isolate); ASSERT(args.length() == 1); - CONVERT_ARG_CHECKED(JSFunction, function, 0); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); int length = function->shared()->scope_info()->ContextLength(); - Context* result; - MaybeObject* maybe_result = - isolate->heap()->AllocateFunctionContext(length, function); - if (!maybe_result->To(&result)) return maybe_result; - - isolate->set_context(result); - - return result; // non-failure + return *isolate->factory()->NewFunctionContext(length, function); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_PushWithContext) { + HandleScope scope(isolate); ASSERT(args.length() == 2); - JSReceiver* extension_object; + Handle<JSReceiver> extension_object; if (args[0]->IsJSReceiver()) { - extension_object = JSReceiver::cast(args[0]); + extension_object = args.at<JSReceiver>(0); } else { - // Convert the object to a proper JavaScript object. - MaybeObject* maybe_js_object = args[0]->ToObject(isolate); - if (!maybe_js_object->To(&extension_object)) { - if (Failure::cast(maybe_js_object)->IsInternalError()) { - HandleScope scope(isolate); - Handle<Object> handle = args.at<Object>(0); - Handle<Object> result = - isolate->factory()->NewTypeError("with_expression", - HandleVector(&handle, 1)); - return isolate->Throw(*result); - } else { - return maybe_js_object; - } + // Try to convert the object to a proper JavaScript object. + MaybeHandle<JSReceiver> maybe_object = + Object::ToObject(isolate, args.at<Object>(0)); + if (!maybe_object.ToHandle(&extension_object)) { + Handle<Object> handle = args.at<Object>(0); + Handle<Object> result = + isolate->factory()->NewTypeError("with_expression", + HandleVector(&handle, 1)); + return isolate->Throw(*result); } } - JSFunction* function; + Handle<JSFunction> function; if (args[1]->IsSmi()) { // A smi sentinel indicates a context nested inside global code rather // than some function. There is a canonical empty function that can be // gotten from the native context. - function = isolate->context()->native_context()->closure(); + function = handle(isolate->context()->native_context()->closure()); } else { - function = JSFunction::cast(args[1]); + function = args.at<JSFunction>(1); } - Context* context; - MaybeObject* maybe_context = - isolate->heap()->AllocateWithContext(function, - isolate->context(), - extension_object); - if (!maybe_context->To(&context)) return maybe_context; - isolate->set_context(context); - return context; + Handle<Context> current(isolate->context()); + Handle<Context> context = isolate->factory()->NewWithContext( + function, current, extension_object); + isolate->set_context(*context); + return *context; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_PushCatchContext) { + HandleScope scope(isolate); ASSERT(args.length() == 3); - String* name = String::cast(args[0]); - Object* thrown_object = args[1]; - JSFunction* function; + CONVERT_ARG_HANDLE_CHECKED(String, name, 0); + CONVERT_ARG_HANDLE_CHECKED(Object, thrown_object, 1); + Handle<JSFunction> function; if (args[2]->IsSmi()) { // A smi sentinel indicates a context nested inside global code rather // than some function. There is a canonical empty function that can be // gotten from the native context. - function = isolate->context()->native_context()->closure(); + function = handle(isolate->context()->native_context()->closure()); } else { - function = JSFunction::cast(args[2]); + function = args.at<JSFunction>(2); } - Context* context; - MaybeObject* maybe_context = - isolate->heap()->AllocateCatchContext(function, - isolate->context(), - name, - thrown_object); - if (!maybe_context->To(&context)) return maybe_context; - isolate->set_context(context); - return context; + Handle<Context> current(isolate->context()); + Handle<Context> context = isolate->factory()->NewCatchContext( + function, current, name, thrown_object); + isolate->set_context(*context); + return *context; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_PushBlockContext) { + HandleScope scope(isolate); ASSERT(args.length() == 2); - ScopeInfo* scope_info = ScopeInfo::cast(args[0]); - JSFunction* function; + CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0); + Handle<JSFunction> function; if (args[1]->IsSmi()) { // A smi sentinel indicates a context nested inside global code rather // than some function. There is a canonical empty function that can be // gotten from the native context. - function = isolate->context()->native_context()->closure(); + function = handle(isolate->context()->native_context()->closure()); } else { - function = JSFunction::cast(args[1]); + function = args.at<JSFunction>(1); } - Context* context; - MaybeObject* maybe_context = - isolate->heap()->AllocateBlockContext(function, - isolate->context(), - scope_info); - if (!maybe_context->To(&context)) return maybe_context; - isolate->set_context(context); - return context; + Handle<Context> current(isolate->context()); + Handle<Context> context = isolate->factory()->NewBlockContext( + function, current, scope_info); + isolate->set_context(*context); + return *context; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSModule) { +RUNTIME_FUNCTION(Runtime_IsJSModule) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); - Object* obj = args[0]; + CONVERT_ARG_CHECKED(Object, obj, 0); return isolate->heap()->ToBoolean(obj->IsJSModule()); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) { +RUNTIME_FUNCTION(RuntimeHidden_PushModuleContext) { SealHandleScope shs(isolate); ASSERT(args.length() == 2); CONVERT_SMI_ARG_CHECKED(index, 0); @@ -9053,7 +9134,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareModules) { +RUNTIME_FUNCTION(RuntimeHidden_DeclareModules) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0); @@ -9073,20 +9154,21 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareModules) { case VAR: case LET: case CONST: - case CONST_HARMONY: { + case CONST_LEGACY: { PropertyAttributes attr = IsImmutableVariableMode(mode) ? FROZEN : SEALED; Handle<AccessorInfo> info = Accessors::MakeModuleExport(name, index, attr); - Handle<Object> result = JSObject::SetAccessor(module, info); - ASSERT(!(result.is_null() || result->IsUndefined())); + Handle<Object> result = + JSObject::SetAccessor(module, info).ToHandleChecked(); + ASSERT(!result->IsUndefined()); USE(result); break; } case MODULE: { Object* referenced_context = Context::cast(host_context)->get(index); Handle<JSModule> value(Context::cast(referenced_context)->module()); - JSReceiver::SetProperty(module, name, value, FROZEN, kStrictMode); + JSReceiver::SetProperty(module, name, value, FROZEN, STRICT).Assert(); break; } case INTERNAL: @@ -9098,7 +9180,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareModules) { } } - JSObject::PreventExtensions(module); + JSObject::PreventExtensions(module).Assert(); } ASSERT(!isolate->has_pending_exception()); @@ -9106,7 +9188,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareModules) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) { +RUNTIME_FUNCTION(RuntimeHidden_DeleteContextSlot) { HandleScope scope(isolate); ASSERT(args.length() == 2); @@ -9137,8 +9219,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) { // the global object, or the subject of a with. Try to delete it // (respecting DONT_DELETE). Handle<JSObject> object = Handle<JSObject>::cast(holder); - Handle<Object> result = JSReceiver::DeleteProperty(object, name); - RETURN_IF_EMPTY_HANDLE(isolate, result); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + JSReceiver::DeleteProperty(object, name)); return *result; } @@ -9153,12 +9237,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) { // allocated by the caller, and passed as a pointer in a hidden first parameter. #ifdef V8_HOST_ARCH_64_BIT struct ObjectPair { - MaybeObject* x; - MaybeObject* y; + Object* x; + Object* y; }; -static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) { +static inline ObjectPair MakePair(Object* x, Object* y) { ObjectPair result = {x, y}; // Pointers x and y returned in rax and rdx, in AMD-x64-abi. // In Win64 they are assigned to a hidden first argument. @@ -9166,20 +9250,18 @@ static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) { } #else typedef uint64_t ObjectPair; -static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) { +static inline ObjectPair MakePair(Object* x, Object* y) { +#if defined(V8_TARGET_LITTLE_ENDIAN) return reinterpret_cast<uint32_t>(x) | (reinterpret_cast<ObjectPair>(y) << 32); -} +#elif defined(V8_TARGET_BIG_ENDIAN) + return reinterpret_cast<uint32_t>(y) | + (reinterpret_cast<ObjectPair>(x) << 32); +#else +#error Unknown endianness #endif - - -static inline MaybeObject* Unhole(Heap* heap, - MaybeObject* x, - PropertyAttributes attributes) { - ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0); - USE(attributes); - return x->IsTheHole() ? heap->undefined_value() : x; } +#endif static Object* ComputeReceiverForNonGlobal(Isolate* isolate, @@ -9197,9 +9279,8 @@ static Object* ComputeReceiverForNonGlobal(Isolate* isolate, if (constructor != context_extension_function) return holder; // Fall back to using the global object as the implicit receiver if // the property turns out to be a local variable allocated in a - // context extension object - introduced via eval. Implicit global - // receivers are indicated with the hole value. - return isolate->heap()->the_hole_value(); + // context extension object - introduced via eval. + return isolate->heap()->undefined_value(); } @@ -9225,7 +9306,7 @@ static ObjectPair LoadContextSlotHelper(Arguments args, &attributes, &binding_flags); if (isolate->has_pending_exception()) { - return MakePair(Failure::Exception(), NULL); + return MakePair(isolate->heap()->exception(), NULL); } // If the index is non-negative, the slot has been found in a context. @@ -9233,11 +9314,7 @@ static ObjectPair LoadContextSlotHelper(Arguments args, ASSERT(holder->IsContext()); // If the "property" we were looking for is a local variable, the // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3. - // - // Use the hole as the receiver to signal that the receiver is implicit - // and that the global receiver should be used (as distinguished from an - // explicit receiver that happens to be a global object). - Handle<Object> receiver = isolate->factory()->the_hole_value(); + Handle<Object> receiver = isolate->factory()->undefined_value(); Object* value = Context::cast(*holder)->get(index); // Check for uninitialized bindings. switch (binding_flags) { @@ -9256,7 +9333,11 @@ static ObjectPair LoadContextSlotHelper(Arguments args, ASSERT(!value->IsTheHole()); return MakePair(value, *receiver); case IMMUTABLE_CHECK_INITIALIZED: - return MakePair(Unhole(isolate->heap(), value, attributes), *receiver); + if (value->IsTheHole()) { + ASSERT((attributes & READ_ONLY) != 0); + value = isolate->heap()->undefined_value(); + } + return MakePair(value, *receiver); case MISSING_BINDING: UNREACHABLE(); return MakePair(NULL, NULL); @@ -9272,15 +9353,19 @@ static ObjectPair LoadContextSlotHelper(Arguments args, // GetProperty below can cause GC. Handle<Object> receiver_handle( object->IsGlobalObject() - ? GlobalObject::cast(*object)->global_receiver() + ? Object::cast(isolate->heap()->undefined_value()) : object->IsJSProxy() ? static_cast<Object*>(*object) : ComputeReceiverForNonGlobal(isolate, JSObject::cast(*object)), isolate); // No need to unhole the value here. This is taken care of by the // GetProperty function. - MaybeObject* value = object->GetProperty(*name); - return MakePair(value, *receiver_handle); + Handle<Object> value; + ASSIGN_RETURN_ON_EXCEPTION_VALUE( + isolate, value, + Object::GetProperty(object, name), + MakePair(isolate->heap()->exception(), NULL)); + return MakePair(*value, *receiver_handle); } if (throw_error) { @@ -9297,26 +9382,24 @@ static ObjectPair LoadContextSlotHelper(Arguments args, } -RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) { +RUNTIME_FUNCTION_RETURN_PAIR(RuntimeHidden_LoadContextSlot) { return LoadContextSlotHelper(args, isolate, true); } -RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) { +RUNTIME_FUNCTION_RETURN_PAIR(RuntimeHidden_LoadContextSlotNoReferenceError) { return LoadContextSlotHelper(args, isolate, false); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) { +RUNTIME_FUNCTION(RuntimeHidden_StoreContextSlot) { HandleScope scope(isolate); ASSERT(args.length() == 4); - Handle<Object> value(args[0], isolate); + CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); CONVERT_ARG_HANDLE_CHECKED(Context, context, 1); CONVERT_ARG_HANDLE_CHECKED(String, name, 2); - CONVERT_LANGUAGE_MODE_ARG(language_mode, 3); - StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE) - ? kNonStrictMode : kStrictMode; + CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 3); int index; PropertyAttributes attributes; @@ -9327,7 +9410,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) { &index, &attributes, &binding_flags); - if (isolate->has_pending_exception()) return Failure::Exception(); + if (isolate->has_pending_exception()) return isolate->heap()->exception(); if (index >= 0) { // The property was found in a context slot. @@ -9343,7 +9426,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) { if ((attributes & READ_ONLY) == 0) { // Context is a fixed array and set cannot fail. context->set(index, *value); - } else if (strict_mode == kStrictMode) { + } else if (strict_mode == STRICT) { // Setting read only property in strict mode. Handle<Object> error = isolate->factory()->NewTypeError("strict_cannot_assign", @@ -9365,25 +9448,25 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) { // The property was not found. ASSERT(attributes == ABSENT); - if (strict_mode == kStrictMode) { + if (strict_mode == STRICT) { // Throw in strict mode (assignment to undefined variable). Handle<Object> error = isolate->factory()->NewReferenceError( "not_defined", HandleVector(&name, 1)); return isolate->Throw(*error); } - // In non-strict mode, the property is added to the global object. + // In sloppy mode, the property is added to the global object. attributes = NONE; object = Handle<JSReceiver>(isolate->context()->global_object()); } // Set the property if it's not read only or doesn't yet exist. if ((attributes & READ_ONLY) == 0 || - (object->GetLocalPropertyAttribute(*name) == ABSENT)) { - RETURN_IF_EMPTY_HANDLE( + (JSReceiver::GetOwnPropertyAttributes(object, name) == ABSENT)) { + RETURN_FAILURE_ON_EXCEPTION( isolate, JSReceiver::SetProperty(object, name, value, NONE, strict_mode)); - } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) { + } else if (strict_mode == STRICT && (attributes & READ_ONLY) != 0) { // Setting read only property in strict mode. Handle<Object> error = isolate->factory()->NewTypeError( @@ -9394,7 +9477,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) { +RUNTIME_FUNCTION(RuntimeHidden_Throw) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -9402,7 +9485,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) { +RUNTIME_FUNCTION(RuntimeHidden_ReThrow) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -9410,18 +9493,17 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) { +RUNTIME_FUNCTION(RuntimeHidden_PromoteScheduledException) { SealHandleScope shs(isolate); - ASSERT_EQ(0, args.length()); + ASSERT(args.length() == 0); return isolate->PromoteScheduledException(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) { +RUNTIME_FUNCTION(RuntimeHidden_ThrowReferenceError) { HandleScope scope(isolate); ASSERT(args.length() == 1); - - Handle<Object> name(args[0], isolate); + CONVERT_ARG_HANDLE_CHECKED(Object, name, 0); Handle<Object> reference_error = isolate->factory()->NewReferenceError("not_defined", HandleVector(&name, 1)); @@ -9429,7 +9511,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowNotDateError) { +RUNTIME_FUNCTION(RuntimeHidden_ThrowNotDateError) { HandleScope scope(isolate); ASSERT(args.length() == 0); return isolate->Throw(*isolate->factory()->NewTypeError( @@ -9437,38 +9519,28 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowNotDateError) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowMessage) { - HandleScope scope(isolate); - ASSERT(args.length() == 1); - CONVERT_SMI_ARG_CHECKED(message_id, 0); - const char* message = GetBailoutReason( - static_cast<BailoutReason>(message_id)); - Handle<Name> message_handle = - isolate->factory()->NewStringFromAscii(CStrVector(message)); - return isolate->Throw(*message_handle); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) { +RUNTIME_FUNCTION(RuntimeHidden_StackGuard) { SealHandleScope shs(isolate); ASSERT(args.length() == 0); // First check if this is a real stack overflow. - if (isolate->stack_guard()->IsStackOverflow()) { + StackLimitCheck check(isolate); + if (check.JsHasOverflowed()) { return isolate->StackOverflow(); } - return Execution::HandleStackGuardInterrupt(isolate); + return isolate->stack_guard()->HandleInterrupts(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_TryInstallRecompiledCode) { +RUNTIME_FUNCTION(RuntimeHidden_TryInstallOptimizedCode) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); // First check if this is a real stack overflow. - if (isolate->stack_guard()->IsStackOverflow()) { + StackLimitCheck check(isolate); + if (check.JsHasOverflowed()) { SealHandleScope shs(isolate); return isolate->StackOverflow(); } @@ -9479,10 +9551,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TryInstallRecompiledCode) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) { +RUNTIME_FUNCTION(RuntimeHidden_Interrupt) { SealHandleScope shs(isolate); ASSERT(args.length() == 0); - return Execution::HandleStackGuardInterrupt(isolate); + return isolate->stack_guard()->HandleInterrupts(); } @@ -9515,7 +9587,7 @@ static void PrintTransition(Isolate* isolate, Object* result) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) { +RUNTIME_FUNCTION(Runtime_TraceEnter) { SealHandleScope shs(isolate); ASSERT(args.length() == 0); PrintTransition(isolate, NULL); @@ -9523,14 +9595,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) { +RUNTIME_FUNCTION(Runtime_TraceExit) { SealHandleScope shs(isolate); - PrintTransition(isolate, args[0]); - return args[0]; // return TOS + ASSERT(args.length() == 1); + CONVERT_ARG_CHECKED(Object, obj, 0); + PrintTransition(isolate, obj); + return obj; // return TOS } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) { +RUNTIME_FUNCTION(Runtime_DebugPrint) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); @@ -9561,7 +9635,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) { +RUNTIME_FUNCTION(Runtime_DebugTrace) { SealHandleScope shs(isolate); ASSERT(args.length() == 0); isolate->PrintStack(stdout); @@ -9569,45 +9643,45 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_DateCurrentTime) { + HandleScope scope(isolate); ASSERT(args.length() == 0); + if (FLAG_log_timer_events) LOG(isolate, CurrentTimeEvent()); // According to ECMA-262, section 15.9.1, page 117, the precision of // the number in a Date object representing a particular instant in // time is milliseconds. Therefore, we floor the result of getting // the OS time. - double millis = floor(OS::TimeCurrentMillis()); - return isolate->heap()->NumberFromDouble(millis); + double millis = std::floor(OS::TimeCurrentMillis()); + return *isolate->factory()->NewNumber(millis); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) { +RUNTIME_FUNCTION(Runtime_DateParseString) { HandleScope scope(isolate); ASSERT(args.length() == 2); - CONVERT_ARG_HANDLE_CHECKED(String, str, 0); - FlattenString(str); - CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1); + RUNTIME_ASSERT(output->HasFastElements()); JSObject::EnsureCanContainHeapObjectElements(output); RUNTIME_ASSERT(output->HasFastObjectElements()); + Handle<FixedArray> output_array(FixedArray::cast(output->elements())); + RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); + str = String::Flatten(str); DisallowHeapAllocation no_gc; - FixedArray* output_array = FixedArray::cast(output->elements()); - RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); bool result; String::FlatContent str_content = str->GetFlatContent(); if (str_content.IsAscii()) { result = DateParser::Parse(str_content.ToOneByteVector(), - output_array, + *output_array, isolate->unicode_cache()); } else { ASSERT(str_content.IsTwoByte()); result = DateParser::Parse(str_content.ToUC16Vector(), - output_array, + *output_array, isolate->unicode_cache()); } @@ -9619,65 +9693,86 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_DateLocalTimezone) { + HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_DOUBLE_ARG_CHECKED(x, 0); - int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x)); - const char* zone = OS::LocalTimezone(static_cast<double>(time)); - return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone)); + RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs && + x <= DateCache::kMaxTimeBeforeUTCInMs); + const char* zone = + isolate->date_cache()->LocalTimezone(static_cast<int64_t>(x)); + Handle<String> result = isolate->factory()->NewStringFromUtf8( + CStrVector(zone)).ToHandleChecked(); + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_DateToUTC) { + HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_DOUBLE_ARG_CHECKED(x, 0); + RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs && + x <= DateCache::kMaxTimeBeforeUTCInMs); int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x)); - return isolate->heap()->NumberFromDouble(static_cast<double>(time)); + return *isolate->factory()->NewNumber(static_cast<double>(time)); +} + + +RUNTIME_FUNCTION(Runtime_DateCacheVersion) { + HandleScope hs(isolate); + ASSERT(args.length() == 0); + if (!isolate->eternal_handles()->Exists(EternalHandles::DATE_CACHE_VERSION)) { + Handle<FixedArray> date_cache_version = + isolate->factory()->NewFixedArray(1, TENURED); + date_cache_version->set(0, Smi::FromInt(0)); + isolate->eternal_handles()->CreateSingleton( + isolate, *date_cache_version, EternalHandles::DATE_CACHE_VERSION); + } + Handle<FixedArray> date_cache_version = + Handle<FixedArray>::cast(isolate->eternal_handles()->GetSingleton( + EternalHandles::DATE_CACHE_VERSION)); + // Return result as a JS array. + Handle<JSObject> result = + isolate->factory()->NewJSObject(isolate->array_function()); + JSArray::SetContent(Handle<JSArray>::cast(result), date_cache_version); + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) { +RUNTIME_FUNCTION(Runtime_GlobalReceiver) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); - Object* global = args[0]; + CONVERT_ARG_CHECKED(Object, global, 0); if (!global->IsJSGlobalObject()) return isolate->heap()->null_value(); return JSGlobalObject::cast(global)->global_receiver(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAttachedGlobal) { +RUNTIME_FUNCTION(Runtime_IsAttachedGlobal) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); - Object* global = args[0]; + CONVERT_ARG_CHECKED(Object, global, 0); if (!global->IsJSGlobalObject()) return isolate->heap()->false_value(); return isolate->heap()->ToBoolean( !JSGlobalObject::cast(global)->IsDetached()); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) { +RUNTIME_FUNCTION(Runtime_ParseJson) { HandleScope scope(isolate); - ASSERT_EQ(1, args.length()); + ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(String, source, 0); - source = Handle<String>(FlattenGetString(source)); + source = String::Flatten(source); // Optimized fast case where we only have ASCII characters. Handle<Object> result; - if (source->IsSeqOneByteString()) { - result = JsonParser<true>::Parse(source); - } else { - result = JsonParser<false>::Parse(source); - } - if (result.is_null()) { - // Syntax error or stack overflow in scanner. - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + source->IsSeqOneByteString() ? JsonParser<true>::Parse(source) + : JsonParser<false>::Parse(source)); return *result; } @@ -9699,15 +9794,73 @@ bool CodeGenerationFromStringsAllowed(Isolate* isolate, } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { +// Walk up the stack expecting: +// - Runtime_CompileString +// - JSFunction callee (eval, Function constructor, etc) +// - call() (maybe) +// - apply() (maybe) +// - bind() (maybe) +// - JSFunction caller (maybe) +// +// return true if the caller has the same security token as the callee +// or if an exit frame was hit, in which case allow it through, as it could +// have come through the api. +static bool TokensMatchForCompileString(Isolate* isolate) { + MaybeHandle<JSFunction> callee; + bool exit_handled = true; + bool tokens_match = true; + bool done = false; + for (StackFrameIterator it(isolate); !it.done() && !done; it.Advance()) { + StackFrame* raw_frame = it.frame(); + if (!raw_frame->is_java_script()) { + if (raw_frame->is_exit()) exit_handled = false; + continue; + } + JavaScriptFrame* outer_frame = JavaScriptFrame::cast(raw_frame); + List<FrameSummary> frames(FLAG_max_inlining_levels + 1); + outer_frame->Summarize(&frames); + for (int i = frames.length() - 1; i >= 0 && !done; --i) { + FrameSummary& frame = frames[i]; + Handle<JSFunction> fun = frame.function(); + // Capture the callee function. + if (callee.is_null()) { + callee = fun; + exit_handled = true; + continue; + } + // Exit condition. + Handle<Context> context(callee.ToHandleChecked()->context()); + if (!fun->context()->HasSameSecurityTokenAs(*context)) { + tokens_match = false; + done = true; + continue; + } + // Skip bound functions in correct origin. + if (fun->shared()->bound()) { + exit_handled = true; + continue; + } + done = true; + } + } + return !exit_handled || tokens_match; +} + + +RUNTIME_FUNCTION(Runtime_CompileString) { HandleScope scope(isolate); - ASSERT_EQ(2, args.length()); + ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(String, source, 0); CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1); // Extract native context. Handle<Context> context(isolate->context()->native_context()); + // Filter cross security context calls. + if (!TokensMatchForCompileString(isolate)) { + return isolate->heap()->undefined_value(); + } + // Check if native context allows code generation from // strings. Throw an exception if it doesn't. if (context->allow_code_gen_from_strings()->IsFalse() && @@ -9721,13 +9874,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { // Compile source string in the native context. ParseRestriction restriction = function_literal_only ? ONLY_SINGLE_FUNCTION_LITERAL : NO_PARSE_RESTRICTION; - Handle<SharedFunctionInfo> shared = Compiler::CompileEval( - source, context, true, CLASSIC_MODE, restriction, RelocInfo::kNoPosition); - RETURN_IF_EMPTY_HANDLE(isolate, shared); - Handle<JSFunction> fun = - isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, - context, - NOT_TENURED); + Handle<JSFunction> fun; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, fun, + Compiler::GetFunctionFromEval( + source, context, SLOPPY, restriction, RelocInfo::kNoPosition)); return *fun; } @@ -9735,7 +9886,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { static ObjectPair CompileGlobalEval(Isolate* isolate, Handle<String> source, Handle<Object> receiver, - LanguageMode language_mode, + StrictMode strict_mode, int scope_position) { Handle<Context> context = Handle<Context>(isolate->context()); Handle<Context> native_context = Handle<Context>(context->native_context()); @@ -9748,28 +9899,23 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, native_context->ErrorMessageForCodeGenerationFromStrings(); isolate->Throw(*isolate->factory()->NewEvalError( "code_gen_from_strings", HandleVector<Object>(&error_message, 1))); - return MakePair(Failure::Exception(), NULL); + return MakePair(isolate->heap()->exception(), NULL); } // Deal with a normal eval call with a string argument. Compile it // and return the compiled function bound in the local context. - Handle<SharedFunctionInfo> shared = Compiler::CompileEval( - source, - context, - context->IsNativeContext(), - language_mode, - NO_PARSE_RESTRICTION, - scope_position); - RETURN_IF_EMPTY_HANDLE_VALUE(isolate, shared, - MakePair(Failure::Exception(), NULL)); - Handle<JSFunction> compiled = - isolate->factory()->NewFunctionFromSharedFunctionInfo( - shared, context, NOT_TENURED); + static const ParseRestriction restriction = NO_PARSE_RESTRICTION; + Handle<JSFunction> compiled; + ASSIGN_RETURN_ON_EXCEPTION_VALUE( + isolate, compiled, + Compiler::GetFunctionFromEval( + source, context, strict_mode, restriction, scope_position), + MakePair(isolate->heap()->exception(), NULL)); return MakePair(*compiled, *receiver); } -RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) { +RUNTIME_FUNCTION_RETURN_PAIR(RuntimeHidden_ResolvePossiblyDirectEval) { HandleScope scope(isolate); ASSERT(args.length() == 5); @@ -9782,65 +9928,50 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) { // the first argument without doing anything). if (*callee != isolate->native_context()->global_eval_fun() || !args[1]->IsString()) { - return MakePair(*callee, isolate->heap()->the_hole_value()); + return MakePair(*callee, isolate->heap()->undefined_value()); } - CONVERT_LANGUAGE_MODE_ARG(language_mode, 3); + ASSERT(args[3]->IsSmi()); + ASSERT(args.smi_at(3) == SLOPPY || args.smi_at(3) == STRICT); + StrictMode strict_mode = static_cast<StrictMode>(args.smi_at(3)); ASSERT(args[4]->IsSmi()); return CompileGlobalEval(isolate, args.at<String>(1), args.at<Object>(2), - language_mode, + strict_mode, args.smi_at(4)); } -// Allocate a block of memory in the given space (filled with a filler). -// Used as a fall-back for generated code when the space is full. -static MaybeObject* Allocate(Isolate* isolate, - int size, - bool double_align, - AllocationSpace space) { - Heap* heap = isolate->heap(); - RUNTIME_ASSERT(IsAligned(size, kPointerSize)); - RUNTIME_ASSERT(size > 0); - RUNTIME_ASSERT(size <= heap->MaxRegularSpaceAllocationSize()); - HeapObject* allocation; - { MaybeObject* maybe_allocation = heap->AllocateRaw(size, space, space); - if (!maybe_allocation->To(&allocation)) return maybe_allocation; - } -#ifdef DEBUG - MemoryChunk* chunk = MemoryChunk::FromAddress(allocation->address()); - ASSERT(chunk->owner()->identity() == space); -#endif - heap->CreateFillerObjectAt(allocation->address(), size); - return allocation; -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_AllocateInNewSpace) { + HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_SMI_ARG_CHECKED(size, 0); - return Allocate(isolate, size, false, NEW_SPACE); + RUNTIME_ASSERT(IsAligned(size, kPointerSize)); + RUNTIME_ASSERT(size > 0); + RUNTIME_ASSERT(size <= Page::kMaxRegularHeapObjectSize); + return *isolate->factory()->NewFillerObject(size, false, NEW_SPACE); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInTargetSpace) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(RuntimeHidden_AllocateInTargetSpace) { + HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_SMI_ARG_CHECKED(size, 0); CONVERT_SMI_ARG_CHECKED(flags, 1); + RUNTIME_ASSERT(IsAligned(size, kPointerSize)); + RUNTIME_ASSERT(size > 0); + RUNTIME_ASSERT(size <= Page::kMaxRegularHeapObjectSize); bool double_align = AllocateDoubleAlignFlag::decode(flags); AllocationSpace space = AllocateTargetSpace::decode(flags); - return Allocate(isolate, size, double_align, space); + return *isolate->factory()->NewFillerObject(size, double_align, space); } // Push an object unto an array of objects if it is not already in the // array. Returns true if the element was pushed on the stack and // false otherwise. -RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) { +RUNTIME_FUNCTION(Runtime_PushIfAbsent) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); @@ -9853,10 +9984,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) { } // Strict not needed. Used for cycle detection in Array join implementation. - RETURN_IF_EMPTY_HANDLE(isolate, JSObject::SetFastElement(array, length, - element, - kNonStrictMode, - true)); + RETURN_FAILURE_ON_EXCEPTION( + isolate, + JSObject::SetFastElement(array, length, element, SLOPPY, true)); return isolate->heap()->true_value(); } @@ -9904,14 +10034,14 @@ class ArrayConcatVisitor { // getters on the arrays increasing the length of later arrays // during iteration. // This shouldn't happen in anything but pathological cases. - SetDictionaryMode(index); + SetDictionaryMode(); // Fall-through to dictionary mode. } ASSERT(!fast_elements_); Handle<SeededNumberDictionary> dict( SeededNumberDictionary::cast(*storage_)); Handle<SeededNumberDictionary> result = - isolate_->factory()->DictionaryAtNumberPut(dict, index, elm); + SeededNumberDictionary::AtNumberPut(dict, index, elm); if (!result.is_identical_to(dict)) { // Dictionary needed to grow. clear_storage(); @@ -9925,6 +10055,14 @@ class ArrayConcatVisitor { } else { index_offset_ += delta; } + // If the initial length estimate was off (see special case in visit()), + // but the array blowing the limit didn't contain elements beyond the + // provided-for index range, go to dictionary mode now. + if (fast_elements_ && + index_offset_ > + static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) { + SetDictionaryMode(); + } } bool exceeds_array_limit() { @@ -9935,14 +10073,9 @@ class ArrayConcatVisitor { Handle<JSArray> array = isolate_->factory()->NewJSArray(0); Handle<Object> length = isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); - Handle<Map> map; - if (fast_elements_) { - map = isolate_->factory()->GetElementsTransitionMap(array, - FAST_HOLEY_ELEMENTS); - } else { - map = isolate_->factory()->GetElementsTransitionMap(array, - DICTIONARY_ELEMENTS); - } + Handle<Map> map = JSObject::GetElementsTransitionMap( + array, + fast_elements_ ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS); array->set_map(*map); array->set_length(*length); array->set_elements(*storage_); @@ -9951,19 +10084,18 @@ class ArrayConcatVisitor { private: // Convert storage to dictionary mode. - void SetDictionaryMode(uint32_t index) { + void SetDictionaryMode() { ASSERT(fast_elements_); Handle<FixedArray> current_storage(*storage_); Handle<SeededNumberDictionary> slow_storage( - isolate_->factory()->NewSeededNumberDictionary( - current_storage->length())); + SeededNumberDictionary::New(isolate_, current_storage->length())); uint32_t current_length = static_cast<uint32_t>(current_storage->length()); for (uint32_t i = 0; i < current_length; i++) { HandleScope loop_scope(isolate_); Handle<Object> element(current_storage->get(i), isolate_); if (!element->IsTheHole()) { Handle<SeededNumberDictionary> new_storage = - isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element); + SeededNumberDictionary::AtNumberPut(slow_storage, i, element); if (!new_storage.is_identical_to(slow_storage)) { slow_storage = loop_scope.CloseAndEscape(new_storage); } @@ -9975,8 +10107,7 @@ class ArrayConcatVisitor { } inline void clear_storage() { - isolate_->global_handles()->Destroy( - Handle<Object>::cast(storage_).location()); + GlobalHandles::Destroy(Handle<Object>::cast(storage_).location()); } inline void set_storage(FixedArray* storage) { @@ -10041,16 +10172,13 @@ static uint32_t EstimateElementCount(Handle<JSArray> array) { } break; } - case NON_STRICT_ARGUMENTS_ELEMENTS: - case EXTERNAL_BYTE_ELEMENTS: - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - case EXTERNAL_SHORT_ELEMENTS: - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - case EXTERNAL_INT_ELEMENTS: - case EXTERNAL_UNSIGNED_INT_ELEMENTS: - case EXTERNAL_FLOAT_ELEMENTS: - case EXTERNAL_DOUBLE_ELEMENTS: - case EXTERNAL_PIXEL_ELEMENTS: + case SLOPPY_ARGUMENTS_ELEMENTS: +#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ELEMENTS: \ + case TYPE##_ELEMENTS: \ + + TYPED_ARRAYS(TYPED_ARRAY_CASE) +#undef TYPED_ARRAY_CASE // External arrays are always dense. return length; } @@ -10158,51 +10286,16 @@ static void CollectElementIndices(Handle<JSObject> object, default: { int dense_elements_length; switch (kind) { - case EXTERNAL_PIXEL_ELEMENTS: { - dense_elements_length = - ExternalPixelArray::cast(object->elements())->length(); - break; - } - case EXTERNAL_BYTE_ELEMENTS: { - dense_elements_length = - ExternalByteArray::cast(object->elements())->length(); - break; - } - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { - dense_elements_length = - ExternalUnsignedByteArray::cast(object->elements())->length(); - break; - } - case EXTERNAL_SHORT_ELEMENTS: { - dense_elements_length = - ExternalShortArray::cast(object->elements())->length(); - break; - } - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { - dense_elements_length = - ExternalUnsignedShortArray::cast(object->elements())->length(); - break; - } - case EXTERNAL_INT_ELEMENTS: { - dense_elements_length = - ExternalIntArray::cast(object->elements())->length(); - break; - } - case EXTERNAL_UNSIGNED_INT_ELEMENTS: { - dense_elements_length = - ExternalUnsignedIntArray::cast(object->elements())->length(); - break; - } - case EXTERNAL_FLOAT_ELEMENTS: { - dense_elements_length = - ExternalFloatArray::cast(object->elements())->length(); - break; - } - case EXTERNAL_DOUBLE_ELEMENTS: { - dense_elements_length = - ExternalDoubleArray::cast(object->elements())->length(); - break; +#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ELEMENTS: { \ + dense_elements_length = \ + External##Type##Array::cast(object->elements())->length(); \ + break; \ } + + TYPED_ARRAYS(TYPED_ARRAY_CASE) +#undef TYPED_ARRAY_CASE + default: UNREACHABLE(); dense_elements_length = 0; @@ -10264,8 +10357,10 @@ static bool IterateElements(Isolate* isolate, } else if (JSReceiver::HasElement(receiver, j)) { // Call GetElement on receiver, not its prototype, or getters won't // have the correct receiver. - element_value = Object::GetElement(isolate, receiver, j); - RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false); + ASSIGN_RETURN_ON_EXCEPTION_VALUE( + isolate, element_value, + Object::GetElement(isolate, receiver, j), + false); visitor->visit(j, element_value); } } @@ -10273,8 +10368,14 @@ static bool IterateElements(Isolate* isolate, } case FAST_HOLEY_DOUBLE_ELEMENTS: case FAST_DOUBLE_ELEMENTS: { + // Empty array is FixedArray but not FixedDoubleArray. + if (length == 0) break; // Run through the elements FixedArray and use HasElement and GetElement // to check the prototype for missing elements. + if (receiver->elements()->IsFixedArray()) { + ASSERT(receiver->elements()->length() == 0); + break; + } Handle<FixedDoubleArray> elements( FixedDoubleArray::cast(receiver->elements())); int fast_length = static_cast<int>(length); @@ -10289,9 +10390,11 @@ static bool IterateElements(Isolate* isolate, } else if (JSReceiver::HasElement(receiver, j)) { // Call GetElement on receiver, not its prototype, or getters won't // have the correct receiver. - Handle<Object> element_value = - Object::GetElement(isolate, receiver, j); - RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false); + Handle<Object> element_value; + ASSIGN_RETURN_ON_EXCEPTION_VALUE( + isolate, element_value, + Object::GetElement(isolate, receiver, j), + false); visitor->visit(j, element_value); } } @@ -10309,8 +10412,11 @@ static bool IterateElements(Isolate* isolate, while (j < n) { HandleScope loop_scope(isolate); uint32_t index = indices[j]; - Handle<Object> element = Object::GetElement(isolate, receiver, index); - RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false); + Handle<Object> element; + ASSIGN_RETURN_ON_EXCEPTION_VALUE( + isolate, element, + Object::GetElement(isolate, receiver, index), + false); visitor->visit(index, element); // Skip to next different index (i.e., omit duplicates). do { @@ -10319,8 +10425,8 @@ static bool IterateElements(Isolate* isolate, } break; } - case EXTERNAL_PIXEL_ELEMENTS: { - Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast( + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: { + Handle<ExternalUint8ClampedArray> pixels(ExternalUint8ClampedArray::cast( receiver->elements())); for (uint32_t j = 0; j < length; j++) { Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate); @@ -10328,43 +10434,43 @@ static bool IterateElements(Isolate* isolate, } break; } - case EXTERNAL_BYTE_ELEMENTS: { - IterateExternalArrayElements<ExternalByteArray, int8_t>( + case EXTERNAL_INT8_ELEMENTS: { + IterateExternalArrayElements<ExternalInt8Array, int8_t>( isolate, receiver, true, true, visitor); break; } - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { - IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>( + case EXTERNAL_UINT8_ELEMENTS: { + IterateExternalArrayElements<ExternalUint8Array, uint8_t>( isolate, receiver, true, true, visitor); break; } - case EXTERNAL_SHORT_ELEMENTS: { - IterateExternalArrayElements<ExternalShortArray, int16_t>( + case EXTERNAL_INT16_ELEMENTS: { + IterateExternalArrayElements<ExternalInt16Array, int16_t>( isolate, receiver, true, true, visitor); break; } - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { - IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>( + case EXTERNAL_UINT16_ELEMENTS: { + IterateExternalArrayElements<ExternalUint16Array, uint16_t>( isolate, receiver, true, true, visitor); break; } - case EXTERNAL_INT_ELEMENTS: { - IterateExternalArrayElements<ExternalIntArray, int32_t>( + case EXTERNAL_INT32_ELEMENTS: { + IterateExternalArrayElements<ExternalInt32Array, int32_t>( isolate, receiver, true, false, visitor); break; } - case EXTERNAL_UNSIGNED_INT_ELEMENTS: { - IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>( + case EXTERNAL_UINT32_ELEMENTS: { + IterateExternalArrayElements<ExternalUint32Array, uint32_t>( isolate, receiver, true, false, visitor); break; } - case EXTERNAL_FLOAT_ELEMENTS: { - IterateExternalArrayElements<ExternalFloatArray, float>( + case EXTERNAL_FLOAT32_ELEMENTS: { + IterateExternalArrayElements<ExternalFloat32Array, float>( isolate, receiver, false, false, visitor); break; } - case EXTERNAL_DOUBLE_ELEMENTS: { - IterateExternalArrayElements<ExternalDoubleArray, double>( + case EXTERNAL_FLOAT64_ELEMENTS: { + IterateExternalArrayElements<ExternalFloat64Array, double>( isolate, receiver, false, false, visitor); break; } @@ -10383,7 +10489,7 @@ static bool IterateElements(Isolate* isolate, * TODO(581): Fix non-compliance for very large concatenations and update to * following the ECMAScript 5 specification. */ -RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) { +RUNTIME_FUNCTION(Runtime_ArrayConcat) { HandleScope handle_scope(isolate); ASSERT(args.length() == 1); @@ -10450,12 +10556,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) { // dictionary. bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length; - Handle<FixedArray> storage; - if (fast_case) { - if (kind == FAST_DOUBLE_ELEMENTS) { + if (fast_case && kind == FAST_DOUBLE_ELEMENTS) { + Handle<FixedArrayBase> storage = + isolate->factory()->NewFixedDoubleArray(estimate_result_length); + int j = 0; + if (estimate_result_length > 0) { Handle<FixedDoubleArray> double_storage = - isolate->factory()->NewFixedDoubleArray(estimate_result_length); - int j = 0; + Handle<FixedDoubleArray>::cast(storage); bool failure = false; for (int i = 0; i < argument_count; i++) { Handle<Object> obj(elements->get(i), isolate); @@ -10471,8 +10578,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) { switch (array->map()->elements_kind()) { case FAST_HOLEY_DOUBLE_ELEMENTS: case FAST_DOUBLE_ELEMENTS: { - // Empty fixed array indicates that there are no elements. - if (array->elements()->IsFixedArray()) break; + // Empty array is FixedArray but not FixedDoubleArray. + if (length == 0) break; FixedDoubleArray* elements = FixedDoubleArray::cast(array->elements()); for (uint32_t i = 0; i < length; i++) { @@ -10511,15 +10618,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) { } if (failure) break; } - Handle<JSArray> array = isolate->factory()->NewJSArray(0); - Smi* length = Smi::FromInt(j); - Handle<Map> map; - map = isolate->factory()->GetElementsTransitionMap(array, kind); - array->set_map(*map); - array->set_length(length); - array->set_elements(*double_storage); - return *array; } + Handle<JSArray> array = isolate->factory()->NewJSArray(0); + Smi* length = Smi::FromInt(j); + Handle<Map> map; + map = JSObject::GetElementsTransitionMap(array, kind); + array->set_map(*map); + array->set_length(length); + array->set_elements(*storage); + return *array; + } + + Handle<FixedArray> storage; + if (fast_case) { // The backing storage array must have non-existing elements to preserve // holes across concat operations. storage = isolate->factory()->NewFixedArrayWithHoles( @@ -10529,7 +10640,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) { uint32_t at_least_space_for = estimate_nof_elements + (estimate_nof_elements >> 2); storage = Handle<FixedArray>::cast( - isolate->factory()->NewSeededNumberDictionary(at_least_space_for)); + SeededNumberDictionary::New(isolate, at_least_space_for)); } ArrayConcatVisitor visitor(isolate, storage, fast_case); @@ -10539,7 +10650,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) { if (obj->IsJSArray()) { Handle<JSArray> array = Handle<JSArray>::cast(obj); if (!IterateElements(isolate, array, &visitor)) { - return Failure::Exception(); + return isolate->heap()->exception(); } } else { visitor.visit(0, obj); @@ -10558,7 +10669,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) { // This will not allocate (flatten the string), but it may run // very slowly for very deeply nested ConsStrings. For debugging use only. -RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) { +RUNTIME_FUNCTION(Runtime_GlobalPrint) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); @@ -10578,7 +10689,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) { // and are followed by non-existing element. Does not change the length // property. // Returns the number of non-undefined elements collected. -RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) { +// Returns -1 if hole removal is not supported by this method. +RUNTIME_FUNCTION(Runtime_RemoveArrayHoles) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); @@ -10588,44 +10700,39 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) { // Move contents of argument 0 (an array) to argument 1 (an array) -RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_MoveArrayContents) { + HandleScope scope(isolate); ASSERT(args.length() == 2); - CONVERT_ARG_CHECKED(JSArray, from, 0); - CONVERT_ARG_CHECKED(JSArray, to, 1); - from->ValidateElements(); - to->ValidateElements(); - FixedArrayBase* new_elements = from->elements(); + CONVERT_ARG_HANDLE_CHECKED(JSArray, from, 0); + CONVERT_ARG_HANDLE_CHECKED(JSArray, to, 1); + JSObject::ValidateElements(from); + JSObject::ValidateElements(to); + + Handle<FixedArrayBase> new_elements(from->elements()); ElementsKind from_kind = from->GetElementsKind(); - MaybeObject* maybe_new_map; - maybe_new_map = to->GetElementsTransitionMap(isolate, from_kind); - Object* new_map; - if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; - to->set_map_and_elements(Map::cast(new_map), new_elements); + Handle<Map> new_map = JSObject::GetElementsTransitionMap(to, from_kind); + JSObject::SetMapAndElements(to, new_map, new_elements); to->set_length(from->length()); - Object* obj; - { MaybeObject* maybe_obj = from->ResetElements(); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } + + JSObject::ResetElements(from); from->set_length(Smi::FromInt(0)); - to->ValidateElements(); - return to; + + JSObject::ValidateElements(to); + return *to; } // How many elements does this object/array have? -RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) { +RUNTIME_FUNCTION(Runtime_EstimateNumberOfElements) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); - CONVERT_ARG_CHECKED(JSObject, object, 0); + CONVERT_ARG_CHECKED(JSArray, object, 0); HeapObject* elements = object->elements(); if (elements->IsDictionary()) { int result = SeededNumberDictionary::cast(elements)->NumberOfElements(); return Smi::FromInt(result); - } else if (object->IsJSArray()) { - return JSArray::cast(object)->length(); } else { - return Smi::FromInt(FixedArray::cast(elements)->length()); + return object->length(); } } @@ -10635,7 +10742,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) { // or undefined) or a number representing the positive length of an interval // starting at index 0. // Intervals can span over some keys that are not in the object. -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) { +RUNTIME_FUNCTION(Runtime_GetArrayKeys) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0); @@ -10652,10 +10759,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) { } Handle<JSObject> current = Handle<JSObject>::cast(p); Handle<FixedArray> current_keys = - isolate->factory()->NewFixedArray( - current->NumberOfLocalElements(NONE)); - current->GetLocalElementKeys(*current_keys, NONE); - keys = UnionOfKeys(keys, current_keys); + isolate->factory()->NewFixedArray(current->NumberOfOwnElements(NONE)); + current->GetOwnElementKeys(*current_keys, NONE); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, keys, FixedArray::UnionOfKeys(keys, current_keys)); } // Erase any keys >= length. // TODO(adamk): Remove this step when the contract of %GetArrayKeys @@ -10665,15 +10772,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) { } return *isolate->factory()->NewJSArrayWithElements(keys); } else { - ASSERT(array->HasFastSmiOrObjectElements() || - array->HasFastDoubleElements()); + RUNTIME_ASSERT(array->HasFastSmiOrObjectElements() || + array->HasFastDoubleElements()); uint32_t actual_length = static_cast<uint32_t>(array->elements()->length()); return *isolate->factory()->NewNumberFromUint(Min(actual_length, length)); } } -RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) { +RUNTIME_FUNCTION(Runtime_LookupAccessor) { HandleScope scope(isolate); ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); @@ -10681,18 +10788,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) { CONVERT_SMI_ARG_CHECKED(flag, 2); AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER; if (!receiver->IsJSObject()) return isolate->heap()->undefined_value(); - Handle<Object> result = - JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component); - RETURN_IF_EMPTY_HANDLE(isolate, result); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component)); return *result; } -#ifdef ENABLE_DEBUGGER_SUPPORT -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) { +RUNTIME_FUNCTION(Runtime_DebugBreak) { SealHandleScope shs(isolate); ASSERT(args.length() == 0); - return Execution::DebugBreakHelper(isolate); + isolate->debug()->HandleDebugBreak(); + return isolate->heap()->undefined_value(); } @@ -10712,86 +10820,72 @@ static StackFrame::Id UnwrapFrameId(int wrapped) { // args[0]: debug event listener function to set or null or undefined for // clearing the event listener function // args[1]: object supplied during callback -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) { +RUNTIME_FUNCTION(Runtime_SetDebugEventListener) { SealHandleScope shs(isolate); ASSERT(args.length() == 2); RUNTIME_ASSERT(args[0]->IsJSFunction() || args[0]->IsUndefined() || args[0]->IsNull()); - Handle<Object> callback = args.at<Object>(0); - Handle<Object> data = args.at<Object>(1); - isolate->debugger()->SetEventListener(callback, data); + CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0); + CONVERT_ARG_HANDLE_CHECKED(Object, data, 1); + isolate->debug()->SetEventListener(callback, data); return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) { +RUNTIME_FUNCTION(Runtime_Break) { SealHandleScope shs(isolate); ASSERT(args.length() == 0); - isolate->stack_guard()->DebugBreak(); + isolate->stack_guard()->RequestDebugBreak(); return isolate->heap()->undefined_value(); } -static MaybeObject* DebugLookupResultValue(Heap* heap, - Object* receiver, - Name* name, - LookupResult* result, - bool* caught_exception) { - Object* value; +static Handle<Object> DebugLookupResultValue(Isolate* isolate, + Handle<Object> receiver, + Handle<Name> name, + LookupResult* result, + bool* has_caught = NULL) { + Handle<Object> value = isolate->factory()->undefined_value(); + if (!result->IsFound()) return value; switch (result->type()) { case NORMAL: - value = result->holder()->GetNormalizedProperty(result); - if (value->IsTheHole()) { - return heap->undefined_value(); - } - return value; - case FIELD: { - Object* value; - MaybeObject* maybe_value = - JSObject::cast(result->holder())->FastPropertyAt( - result->representation(), - result->GetFieldIndex().field_index()); - if (!maybe_value->To(&value)) return maybe_value; - if (value->IsTheHole()) { - return heap->undefined_value(); - } - return value; - } + value = JSObject::GetNormalizedProperty( + handle(result->holder(), isolate), result); + break; + case FIELD: + value = JSObject::FastPropertyAt(handle(result->holder(), isolate), + result->representation(), + result->GetFieldIndex()); + break; case CONSTANT: - return result->GetConstant(); + return handle(result->GetConstant(), isolate); case CALLBACKS: { - Object* structure = result->GetCallbackObject(); - if (structure->IsForeign() || structure->IsAccessorInfo()) { - Isolate* isolate = heap->isolate(); - HandleScope scope(isolate); - Handle<Object> value = JSObject::GetPropertyWithCallback( - handle(result->holder(), isolate), - handle(receiver, isolate), - handle(structure, isolate), - handle(name, isolate)); - if (value.is_null()) { - MaybeObject* exception = heap->isolate()->pending_exception(); - heap->isolate()->clear_pending_exception(); - if (caught_exception != NULL) *caught_exception = true; - return exception; + Handle<Object> structure(result->GetCallbackObject(), isolate); + ASSERT(!structure->IsForeign()); + if (structure->IsAccessorInfo()) { + MaybeHandle<Object> obj = JSObject::GetPropertyWithAccessor( + receiver, name, handle(result->holder(), isolate), structure); + if (!obj.ToHandle(&value)) { + value = handle(isolate->pending_exception(), isolate); + isolate->clear_pending_exception(); + if (has_caught != NULL) *has_caught = true; + return value; } - return *value; - } else { - return heap->undefined_value(); } + break; } case INTERCEPTOR: - case TRANSITION: - return heap->undefined_value(); case HANDLER: + break; case NONEXISTENT: UNREACHABLE(); - return heap->undefined_value(); + break; } - UNREACHABLE(); // keep the compiler happy - return heap->undefined_value(); + ASSERT(!value->IsTheHole() || result->IsReadOnly()); + return value->IsTheHole() + ? Handle<Object>::cast(isolate->factory()->undefined_value()) : value; } @@ -10807,7 +10901,7 @@ static MaybeObject* DebugLookupResultValue(Heap* heap, // 4: Setter function if defined // Items 2-4 are only filled if the property has either a getter or a setter // defined through __defineGetter__ and/or __defineSetter__. -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) { +RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) { HandleScope scope(isolate); ASSERT(args.length() == 2); @@ -10822,7 +10916,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) { // could have the assumption that its own native context is the current // context and not some internal debugger context. SaveContext save(isolate); - if (isolate->debug()->InDebugger()) { + if (isolate->debug()->in_debug_scope()) { isolate->set_context(*isolate->debug()->debugger_entry()->GetContext()); } @@ -10838,27 +10932,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) { uint32_t index; if (name->AsArrayIndex(&index)) { Handle<FixedArray> details = isolate->factory()->NewFixedArray(2); - Object* element_or_char; - { MaybeObject* maybe_element_or_char = - Runtime::GetElementOrCharAt(isolate, obj, index); - if (!maybe_element_or_char->ToObject(&element_or_char)) { - return maybe_element_or_char; - } - } - details->set(0, element_or_char); + Handle<Object> element_or_char; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, element_or_char, + Runtime::GetElementOrCharAt(isolate, obj, index)); + details->set(0, *element_or_char); details->set( 1, PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi()); return *isolate->factory()->NewJSArrayWithElements(details); } // Find the number of objects making up this. - int length = LocalPrototypeChainLength(*obj); + int length = OwnPrototypeChainLength(*obj); - // Try local lookup on each of the objects. + // Try own lookup on each of the objects. Handle<JSObject> jsproto = obj; for (int i = 0; i < length; i++) { LookupResult result(isolate); - jsproto->LocalLookup(*name, &result); + jsproto->LookupOwn(name, &result); if (result.IsFound()) { // LookupResult is not GC safe as it holds raw object pointers. // GC can happen later in this code so put the required fields into @@ -10868,29 +10959,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) { result_callback_obj = Handle<Object>(result.GetCallbackObject(), isolate); } - Smi* property_details = result.GetPropertyDetails().AsSmi(); - // DebugLookupResultValue can cause GC so details from LookupResult needs - // to be copied to handles before this. - bool caught_exception = false; - Object* raw_value; - { MaybeObject* maybe_raw_value = - DebugLookupResultValue(isolate->heap(), *obj, *name, - &result, &caught_exception); - if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value; - } - Handle<Object> value(raw_value, isolate); + + + bool has_caught = false; + Handle<Object> value = DebugLookupResultValue( + isolate, obj, name, &result, &has_caught); // If the callback object is a fixed array then it contains JavaScript // getter and/or setter. - bool hasJavaScriptAccessors = result.IsPropertyCallbacks() && - result_callback_obj->IsAccessorPair(); + bool has_js_accessors = result.IsPropertyCallbacks() && + result_callback_obj->IsAccessorPair(); Handle<FixedArray> details = - isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2); + isolate->factory()->NewFixedArray(has_js_accessors ? 5 : 2); details->set(0, *value); - details->set(1, property_details); - if (hasJavaScriptAccessors) { + details->set(1, result.GetPropertyDetails().AsSmi()); + if (has_js_accessors) { AccessorPair* accessors = AccessorPair::cast(*result_callback_obj); - details->set(2, isolate->heap()->ToBoolean(caught_exception)); + details->set(2, isolate->heap()->ToBoolean(has_caught)); details->set(3, accessors->GetComponent(ACCESSOR_GETTER)); details->set(4, accessors->GetComponent(ACCESSOR_SETTER)); } @@ -10906,7 +10991,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) { +RUNTIME_FUNCTION(Runtime_DebugGetProperty) { HandleScope scope(isolate); ASSERT(args.length() == 2); @@ -10915,17 +11000,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) { CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); LookupResult result(isolate); - obj->Lookup(*name, &result); - if (result.IsFound()) { - return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL); - } - return isolate->heap()->undefined_value(); + obj->Lookup(name, &result); + return *DebugLookupResultValue(isolate, obj, name, &result); } // Return the property type calculated from the property details. // args[0]: smi with property details. -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) { +RUNTIME_FUNCTION(Runtime_DebugPropertyTypeFromDetails) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); @@ -10935,7 +11017,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) { // Return the property attribute calculated from the property details. // args[0]: smi with property details. -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) { +RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); @@ -10945,7 +11027,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) { // Return the property insertion index calculated from the property details. // args[0]: smi with property details. -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) { +RUNTIME_FUNCTION(Runtime_DebugPropertyIndexFromDetails) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); @@ -10957,17 +11039,17 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) { // Return property value from named interceptor. // args[0]: object // args[1]: property name -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) { +RUNTIME_FUNCTION(Runtime_DebugNamedInterceptorPropertyValue) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); RUNTIME_ASSERT(obj->HasNamedInterceptor()); CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); - PropertyAttributes attributes; - Handle<Object> result = - JSObject::GetPropertyWithInterceptor(obj, obj, name, &attributes); - RETURN_IF_EMPTY_HANDLE(isolate, result); + Handle<Object> result; + LookupIterator it(obj, name, obj); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, JSObject::GetProperty(&it)); return *result; } @@ -10975,42 +11057,40 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) { // Return element value from indexed interceptor. // args[0]: object // args[1]: index -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) { +RUNTIME_FUNCTION(Runtime_DebugIndexedInterceptorElementValue) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); RUNTIME_ASSERT(obj->HasIndexedInterceptor()); CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, JSObject::GetElementWithInterceptor(obj, obj, index)); + return *result; +} + - return obj->GetElementWithInterceptor(*obj, index); +static bool CheckExecutionState(Isolate* isolate, int break_id) { + return !isolate->debug()->debug_context().is_null() && + isolate->debug()->break_id() != 0 && + isolate->debug()->break_id() == break_id; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) { +RUNTIME_FUNCTION(Runtime_CheckExecutionState) { SealHandleScope shs(isolate); - ASSERT(args.length() >= 1); + ASSERT(args.length() == 1); CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); - // Check that the break id is valid. - if (isolate->debug()->break_id() == 0 || - break_id != isolate->debug()->break_id()) { - return isolate->Throw( - isolate->heap()->illegal_execution_state_string()); - } - + RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); return isolate->heap()->true_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) { +RUNTIME_FUNCTION(Runtime_GetFrameCount) { HandleScope scope(isolate); ASSERT(args.length() == 1); - - // Check arguments. - Object* result; - { MaybeObject* maybe_result = Runtime_CheckExecutionState( - RUNTIME_ARGUMENTS(isolate, args)); - if (!maybe_result->ToObject(&result)) return maybe_result; - } + CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); + RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); // Count all frames which are relevant to debugging stack trace. int n = 0; @@ -11144,16 +11224,12 @@ static SaveContext* FindSavedContextForFrame(Isolate* isolate, // Arguments name, value // Locals name, value // Return value if any -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { +RUNTIME_FUNCTION(Runtime_GetFrameDetails) { HandleScope scope(isolate); ASSERT(args.length() == 2); + CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); + RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); - // Check arguments. - Object* check; - { MaybeObject* maybe_check = Runtime_CheckExecutionState( - RUNTIME_ARGUMENTS(isolate, args)); - if (!maybe_check->ToObject(&check)) return maybe_check; - } CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); Heap* heap = isolate->heap(); @@ -11201,31 +11277,44 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { ASSERT(*scope_info != ScopeInfo::Empty(isolate)); // Get the locals names and values into a temporary array. - // - // TODO(1240907): Hide compiler-introduced stack variables - // (e.g. .result)? For users of the debugger, they will probably be - // confusing. + int local_count = scope_info->LocalCount(); + for (int slot = 0; slot < scope_info->LocalCount(); ++slot) { + // Hide compiler-introduced temporary variables, whether on the stack or on + // the context. + if (scope_info->LocalIsSynthetic(slot)) + local_count--; + } + Handle<FixedArray> locals = - isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2); + isolate->factory()->NewFixedArray(local_count * 2); // Fill in the values of the locals. + int local = 0; int i = 0; for (; i < scope_info->StackLocalCount(); ++i) { // Use the value from the stack. - locals->set(i * 2, scope_info->LocalName(i)); - locals->set(i * 2 + 1, frame_inspector.GetExpression(i)); + if (scope_info->LocalIsSynthetic(i)) + continue; + locals->set(local * 2, scope_info->LocalName(i)); + locals->set(local * 2 + 1, frame_inspector.GetExpression(i)); + local++; } - if (i < scope_info->LocalCount()) { + if (local < local_count) { // Get the context containing declarations. Handle<Context> context( Context::cast(it.frame()->context())->declaration_context()); for (; i < scope_info->LocalCount(); ++i) { + if (scope_info->LocalIsSynthetic(i)) + continue; Handle<String> name(scope_info->LocalName(i)); VariableMode mode; InitializationFlag init_flag; - locals->set(i * 2, *name); - locals->set(i * 2 + 1, context->get( - scope_info->ContextSlotIndex(*name, &mode, &init_flag))); + locals->set(local * 2, *name); + int context_slot_index = + ScopeInfo::ContextSlotIndex(scope_info, name, &mode, &init_flag); + Object* value = context->get(context_slot_index); + locals->set(local * 2 + 1, value); + local++; } } @@ -11286,7 +11375,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { // Calculate the size of the result. int details_size = kFrameDetailsFirstDynamicIndex + - 2 * (argument_count + scope_info->LocalCount()) + + 2 * (argument_count + local_count) + (at_return ? 1 : 0); Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); @@ -11301,7 +11390,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { // Add the locals count details->set(kFrameDetailsLocalCountIndex, - Smi::FromInt(scope_info->LocalCount())); + Smi::FromInt(local_count)); // Add the source position. if (position != RelocInfo::kNoPosition) { @@ -11352,7 +11441,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { } // Add locals name and value from the temporary copy from the function frame. - for (int i = 0; i < scope_info->LocalCount() * 2; i++) { + for (int i = 0; i < local_count * 2; i++) { details->set(details_index++, locals->get(i)); } @@ -11366,7 +11455,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { // THE FRAME ITERATOR TO WRAP THE RECEIVER. Handle<Object> receiver(it.frame()->receiver(), isolate); if (!receiver->IsJSObject() && - shared->is_classic_mode() && + shared->strict_mode() == SLOPPY && !function->IsBuiltin()) { // If the receiver is not a JSObject and the function is not a // builtin or strict-mode we have hit an optimization where a @@ -11375,11 +11464,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { // by creating correct wrapper object based on the calling frame's // native context. it.Advance(); - Handle<Context> calling_frames_native_context( - Context::cast(Context::cast(it.frame()->context())->native_context())); - ASSERT(!receiver->IsUndefined() && !receiver->IsNull()); - receiver = - isolate->factory()->ToObject(receiver, calling_frames_native_context); + if (receiver->IsUndefined()) { + Context* context = function->context(); + receiver = handle(context->global_object()->global_receiver()); + } else { + ASSERT(!receiver->IsNull()); + Context* context = Context::cast(it.frame()->context()); + Handle<Context> native_context(Context::cast(context->native_context())); + receiver = Object::ToObject( + isolate, receiver, native_context).ToHandleChecked(); + } } details->set(kFrameDetailsReceiverIndex, *receiver); @@ -11388,9 +11482,18 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { } +static bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info, + Handle<String> parameter_name) { + VariableMode mode; + InitializationFlag flag; + return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &flag) != -1; +} + + // Create a plain JSObject which materializes the local scope for the specified // frame. -static Handle<JSObject> MaterializeStackLocalsWithFrameInspector( +MUST_USE_RESULT +static MaybeHandle<JSObject> MaterializeStackLocalsWithFrameInspector( Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function, @@ -11400,38 +11503,34 @@ static Handle<JSObject> MaterializeStackLocalsWithFrameInspector( // First fill all parameters. for (int i = 0; i < scope_info->ParameterCount(); ++i) { + // Do not materialize the parameter if it is shadowed by a context local. + Handle<String> name(scope_info->ParameterName(i)); + if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; + + HandleScope scope(isolate); Handle<Object> value(i < frame_inspector->GetParametersCount() ? frame_inspector->GetParameter(i) : isolate->heap()->undefined_value(), isolate); ASSERT(!value->IsTheHole()); - RETURN_IF_EMPTY_HANDLE_VALUE( + RETURN_ON_EXCEPTION( isolate, - Runtime::SetObjectProperty(isolate, - target, - Handle<String>(scope_info->ParameterName(i)), - value, - NONE, - kNonStrictMode), - Handle<JSObject>()); + Runtime::SetObjectProperty(isolate, target, name, value, NONE, SLOPPY), + JSObject); } // Second fill all stack locals. for (int i = 0; i < scope_info->StackLocalCount(); ++i) { + if (scope_info->LocalIsSynthetic(i)) continue; + Handle<String> name(scope_info->StackLocalName(i)); Handle<Object> value(frame_inspector->GetExpression(i), isolate); if (value->IsTheHole()) continue; - RETURN_IF_EMPTY_HANDLE_VALUE( + RETURN_ON_EXCEPTION( isolate, - Runtime::SetObjectProperty( - isolate, - target, - Handle<String>(scope_info->StackLocalName(i)), - value, - NONE, - kNonStrictMode), - Handle<JSObject>()); + Runtime::SetObjectProperty(isolate, target, name, value, NONE, SLOPPY), + JSObject); } return target; @@ -11455,28 +11554,35 @@ static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate, // Parameters. for (int i = 0; i < scope_info->ParameterCount(); ++i) { + // Shadowed parameters were not materialized. + Handle<String> name(scope_info->ParameterName(i)); + if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; + ASSERT(!frame->GetParameter(i)->IsTheHole()); HandleScope scope(isolate); - Handle<Object> value = GetProperty( - isolate, target, Handle<String>(scope_info->ParameterName(i))); + Handle<Object> value = + Object::GetPropertyOrElement(target, name).ToHandleChecked(); frame->SetParameterValue(i, *value); } // Stack locals. for (int i = 0; i < scope_info->StackLocalCount(); ++i) { + if (scope_info->LocalIsSynthetic(i)) continue; if (frame->GetExpression(i)->IsTheHole()) continue; HandleScope scope(isolate); - Handle<Object> value = GetProperty( - isolate, target, Handle<String>(scope_info->StackLocalName(i))); + Handle<Object> value = Object::GetPropertyOrElement( + target, + handle(scope_info->StackLocalName(i), isolate)).ToHandleChecked(); frame->SetExpression(i, *value); } } -static Handle<JSObject> MaterializeLocalContext(Isolate* isolate, - Handle<JSObject> target, - Handle<JSFunction> function, - JavaScriptFrame* frame) { +MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext( + Isolate* isolate, + Handle<JSObject> target, + Handle<JSFunction> function, + JavaScriptFrame* frame) { HandleScope scope(isolate); Handle<SharedFunctionInfo> shared(function->shared()); Handle<ScopeInfo> scope_info(shared->scope_info()); @@ -11488,7 +11594,7 @@ static Handle<JSObject> MaterializeLocalContext(Isolate* isolate, Handle<Context> function_context(frame_context->declaration_context()); if (!ScopeInfo::CopyContextLocalsToScopeObject( scope_info, function_context, target)) { - return Handle<JSObject>(); + return MaybeHandle<JSObject>(); } // Finally copy any properties from the function context extension. @@ -11497,24 +11603,24 @@ static Handle<JSObject> MaterializeLocalContext(Isolate* isolate, if (function_context->has_extension() && !function_context->IsNativeContext()) { Handle<JSObject> ext(JSObject::cast(function_context->extension())); - bool threw = false; - Handle<FixedArray> keys = - GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw); - if (threw) return Handle<JSObject>(); + Handle<FixedArray> keys; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, keys, + JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS), + JSObject); for (int i = 0; i < keys->length(); i++) { // Names of variables introduced by eval are strings. ASSERT(keys->get(i)->IsString()); Handle<String> key(String::cast(keys->get(i))); - RETURN_IF_EMPTY_HANDLE_VALUE( + Handle<Object> value; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, value, Object::GetPropertyOrElement(ext, key), JSObject); + RETURN_ON_EXCEPTION( isolate, - Runtime::SetObjectProperty(isolate, - target, - key, - GetProperty(isolate, ext, key), - NONE, - kNonStrictMode), - Handle<JSObject>()); + Runtime::SetObjectProperty( + isolate, target, key, value, NONE, SLOPPY), + JSObject); } } } @@ -11523,7 +11629,7 @@ static Handle<JSObject> MaterializeLocalContext(Isolate* isolate, } -static Handle<JSObject> MaterializeLocalScope( +MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalScope( Isolate* isolate, JavaScriptFrame* frame, int inlined_jsframe_index) { @@ -11532,9 +11638,11 @@ static Handle<JSObject> MaterializeLocalScope( Handle<JSObject> local_scope = isolate->factory()->NewJSObject(isolate->object_function()); - local_scope = MaterializeStackLocalsWithFrameInspector( - isolate, local_scope, function, &frame_inspector); - RETURN_IF_EMPTY_HANDLE_VALUE(isolate, local_scope, Handle<JSObject>()); + ASSIGN_RETURN_ON_EXCEPTION( + isolate, local_scope, + MaterializeStackLocalsWithFrameInspector( + isolate, local_scope, function, &frame_inspector), + JSObject); return MaterializeLocalContext(isolate, local_scope, function, frame); } @@ -11548,11 +11656,11 @@ static bool SetContextLocalValue(Isolate* isolate, Handle<Object> new_value) { for (int i = 0; i < scope_info->ContextLocalCount(); i++) { Handle<String> next_name(scope_info->ContextLocalName(i)); - if (variable_name->Equals(*next_name)) { + if (String::Equals(variable_name, next_name)) { VariableMode mode; InitializationFlag init_flag; int context_index = - scope_info->ContextSlotIndex(*next_name, &mode, &init_flag); + ScopeInfo::ContextSlotIndex(scope_info, next_name, &mode, &init_flag); context->set(context_index, *new_value); return true; } @@ -11580,7 +11688,8 @@ static bool SetLocalVariableValue(Isolate* isolate, // Parameters. for (int i = 0; i < scope_info->ParameterCount(); ++i) { - if (scope_info->ParameterName(i)->Equals(*variable_name)) { + HandleScope scope(isolate); + if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) { frame->SetParameterValue(i, *new_value); // Argument might be shadowed in heap context, don't stop here. default_result = true; @@ -11589,7 +11698,8 @@ static bool SetLocalVariableValue(Isolate* isolate, // Stack locals. for (int i = 0; i < scope_info->StackLocalCount(); ++i) { - if (scope_info->StackLocalName(i)->Equals(*variable_name)) { + HandleScope scope(isolate); + if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) { frame->SetExpression(i, *new_value); return true; } @@ -11614,8 +11724,7 @@ static bool SetLocalVariableValue(Isolate* isolate, // We don't expect this to do anything except replacing // property value. Runtime::SetObjectProperty(isolate, ext, variable_name, new_value, - NONE, - kNonStrictMode); + NONE, SLOPPY).Assert(); return true; } } @@ -11628,8 +11737,9 @@ static bool SetLocalVariableValue(Isolate* isolate, // Create a plain JSObject which materializes the closure content for the // context. -static Handle<JSObject> MaterializeClosure(Isolate* isolate, - Handle<Context> context) { +MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeClosure( + Isolate* isolate, + Handle<Context> context) { ASSERT(context->IsFunctionContext()); Handle<SharedFunctionInfo> shared(context->closure()->shared()); @@ -11643,29 +11753,31 @@ static Handle<JSObject> MaterializeClosure(Isolate* isolate, // Fill all context locals to the context extension. if (!ScopeInfo::CopyContextLocalsToScopeObject( scope_info, context, closure_scope)) { - return Handle<JSObject>(); + return MaybeHandle<JSObject>(); } // Finally copy any properties from the function context extension. This will // be variables introduced by eval. if (context->has_extension()) { Handle<JSObject> ext(JSObject::cast(context->extension())); - bool threw = false; - Handle<FixedArray> keys = - GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw); - if (threw) return Handle<JSObject>(); + Handle<FixedArray> keys; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, keys, + JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS), JSObject); for (int i = 0; i < keys->length(); i++) { + HandleScope scope(isolate); // Names of variables introduced by eval are strings. ASSERT(keys->get(i)->IsString()); Handle<String> key(String::cast(keys->get(i))); - RETURN_IF_EMPTY_HANDLE_VALUE( + Handle<Object> value; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, value, Object::GetPropertyOrElement(ext, key), JSObject); + RETURN_ON_EXCEPTION( isolate, - Runtime::SetObjectProperty(isolate, closure_scope, key, - GetProperty(isolate, ext, key), - NONE, - kNonStrictMode), - Handle<JSObject>()); + Runtime::SetObjectProperty( + isolate, closure_scope, key, value, NONE, SLOPPY), + JSObject); } } @@ -11696,8 +11808,7 @@ static bool SetClosureVariableValue(Isolate* isolate, if (JSReceiver::HasProperty(ext, variable_name)) { // We don't expect this to do anything except replacing property value. Runtime::SetObjectProperty(isolate, ext, variable_name, new_value, - NONE, - kNonStrictMode); + NONE, SLOPPY).Assert(); return true; } } @@ -11708,20 +11819,20 @@ static bool SetClosureVariableValue(Isolate* isolate, // Create a plain JSObject which materializes the scope for the specified // catch context. -static Handle<JSObject> MaterializeCatchScope(Isolate* isolate, - Handle<Context> context) { +MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeCatchScope( + Isolate* isolate, + Handle<Context> context) { ASSERT(context->IsCatchContext()); Handle<String> name(String::cast(context->extension())); Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX), isolate); Handle<JSObject> catch_scope = isolate->factory()->NewJSObject(isolate->object_function()); - RETURN_IF_EMPTY_HANDLE_VALUE( + RETURN_ON_EXCEPTION( isolate, Runtime::SetObjectProperty(isolate, catch_scope, name, thrown_object, - NONE, - kNonStrictMode), - Handle<JSObject>()); + NONE, SLOPPY), + JSObject); return catch_scope; } @@ -11732,7 +11843,7 @@ static bool SetCatchVariableValue(Isolate* isolate, Handle<Object> new_value) { ASSERT(context->IsCatchContext()); Handle<String> name(String::cast(context->extension())); - if (!name->Equals(*variable_name)) { + if (!String::Equals(name, variable_name)) { return false; } context->set(Context::THROWN_OBJECT_INDEX, *new_value); @@ -11742,7 +11853,7 @@ static bool SetCatchVariableValue(Isolate* isolate, // Create a plain JSObject which materializes the block scope for the specified // block context. -static Handle<JSObject> MaterializeBlockScope( +MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeBlockScope( Isolate* isolate, Handle<Context> context) { ASSERT(context->IsBlockContext()); @@ -11756,7 +11867,7 @@ static Handle<JSObject> MaterializeBlockScope( // Fill all context locals. if (!ScopeInfo::CopyContextLocalsToScopeObject( scope_info, context, block_scope)) { - return Handle<JSObject>(); + return MaybeHandle<JSObject>(); } return block_scope; @@ -11765,7 +11876,7 @@ static Handle<JSObject> MaterializeBlockScope( // Create a plain JSObject which materializes the module scope for the specified // module context. -static Handle<JSObject> MaterializeModuleScope( +MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope( Isolate* isolate, Handle<Context> context) { ASSERT(context->IsModuleContext()); @@ -11779,7 +11890,7 @@ static Handle<JSObject> MaterializeModuleScope( // Fill all context locals. if (!ScopeInfo::CopyContextLocalsToScopeObject( scope_info, context, module_scope)) { - return Handle<JSObject>(); + return MaybeHandle<JSObject>(); } return module_scope; @@ -11804,7 +11915,8 @@ class ScopeIterator { ScopeIterator(Isolate* isolate, JavaScriptFrame* frame, - int inlined_jsframe_index) + int inlined_jsframe_index, + bool ignore_nested_scopes = false) : isolate_(isolate), frame_(frame), inlined_jsframe_index_(inlined_jsframe_index), @@ -11828,19 +11940,31 @@ class ScopeIterator { // Return if ensuring debug info failed. return; } - Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info); - // Find the break point where execution has stopped. - BreakLocationIterator break_location_iterator(debug_info, - ALL_BREAK_LOCATIONS); - // pc points to the instruction after the current one, possibly a break - // location as well. So the "- 1" to exclude it from the search. - break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1); - if (break_location_iterator.IsExit()) { - // We are within the return sequence. At the momemt it is not possible to + // Currently it takes too much time to find nested scopes due to script + // parsing. Sometimes we want to run the ScopeIterator as fast as possible + // (for example, while collecting async call stacks on every + // addEventListener call), even if we drop some nested scopes. + // Later we may optimize getting the nested scopes (cache the result?) + // and include nested scopes into the "fast" iteration case as well. + if (!ignore_nested_scopes) { + Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info); + + // Find the break point where execution has stopped. + BreakLocationIterator break_location_iterator(debug_info, + ALL_BREAK_LOCATIONS); + // pc points to the instruction after the current one, possibly a break + // location as well. So the "- 1" to exclude it from the search. + break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1); + + // Within the return sequence at the moment it is not possible to // get a source position which is consistent with the current scope chain. // Thus all nested with, catch and block contexts are skipped and we only // provide the function scope. + ignore_nested_scopes = break_location_iterator.IsExit(); + } + + if (ignore_nested_scopes) { if (scope_info->HasContext()) { context_ = Handle<Context>(context_->declaration_context(), isolate_); } else { @@ -11848,7 +11972,7 @@ class ScopeIterator { context_ = Handle<Context>(context_->previous(), isolate_); } } - if (scope_info->scope_type() != EVAL_SCOPE) { + if (scope_info->scope_type() == FUNCTION_SCOPE) { nested_scope_chain_.Add(scope_info); } } else { @@ -11976,7 +12100,7 @@ class ScopeIterator { } // Return the JavaScript object with the content of the current scope. - Handle<JSObject> ScopeObject() { + MaybeHandle<JSObject> ScopeObject() { ASSERT(!failed_); switch (Type()) { case ScopeIterator::ScopeTypeGlobal: @@ -12139,16 +12263,12 @@ class ScopeIterator { }; -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) { +RUNTIME_FUNCTION(Runtime_GetScopeCount) { HandleScope scope(isolate); ASSERT(args.length() == 2); + CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); + RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); - // Check arguments. - Object* check; - { MaybeObject* maybe_check = Runtime_CheckExecutionState( - RUNTIME_ARGUMENTS(isolate, args)); - if (!maybe_check->ToObject(&check)) return maybe_check; - } CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); // Get the frame where the debugging is performed. @@ -12171,16 +12291,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) { // Returns the list of step-in positions (text offset) in a function of the // stack frame in a range from the current debug break position to the end // of the corresponding statement. -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetStepInPositions) { +RUNTIME_FUNCTION(Runtime_GetStepInPositions) { HandleScope scope(isolate); ASSERT(args.length() == 2); + CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); + RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); - // Check arguments. - Object* check; - { MaybeObject* maybe_check = Runtime_CheckExecutionState( - RUNTIME_ARGUMENTS(isolate, args)); - if (!maybe_check->ToObject(&check)) return maybe_check; - } CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); // Get the frame where the debugging is performed. @@ -12231,9 +12347,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetStepInPositions) { if (accept) { if (break_location_iterator.IsStepInLocation(isolate)) { Smi* position_value = Smi::FromInt(break_location_iterator.position()); - JSObject::SetElement(array, len, - Handle<Object>(position_value, isolate), - NONE, kNonStrictMode); + RETURN_FAILURE_ON_EXCEPTION( + isolate, + JSObject::SetElement(array, len, + Handle<Object>(position_value, isolate), + NONE, SLOPPY)); len++; } } @@ -12253,7 +12371,8 @@ static const int kScopeDetailsObjectIndex = 1; static const int kScopeDetailsSize = 2; -static MaybeObject* MaterializeScopeDetails(Isolate* isolate, +MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScopeDetails( + Isolate* isolate, ScopeIterator* it) { // Calculate the size of the result. int details_size = kScopeDetailsSize; @@ -12261,11 +12380,12 @@ static MaybeObject* MaterializeScopeDetails(Isolate* isolate, // Fill in scope details. details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type())); - Handle<JSObject> scope_object = it->ScopeObject(); - RETURN_IF_EMPTY_HANDLE(isolate, scope_object); + Handle<JSObject> scope_object; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, scope_object, it->ScopeObject(), JSObject); details->set(kScopeDetailsObjectIndex, *scope_object); - return *isolate->factory()->NewJSArrayWithElements(details); + return isolate->factory()->NewJSArrayWithElements(details); } @@ -12278,16 +12398,12 @@ static MaybeObject* MaterializeScopeDetails(Isolate* isolate, // The array returned contains the following information: // 0: Scope type // 1: Scope object -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) { +RUNTIME_FUNCTION(Runtime_GetScopeDetails) { HandleScope scope(isolate); ASSERT(args.length() == 4); + CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); + RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); - // Check arguments. - Object* check; - { MaybeObject* maybe_check = Runtime_CheckExecutionState( - RUNTIME_ARGUMENTS(isolate, args)); - if (!maybe_check->ToObject(&check)) return maybe_check; - } CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); @@ -12306,11 +12422,60 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) { if (it.Done()) { return isolate->heap()->undefined_value(); } - return MaterializeScopeDetails(isolate, &it); + Handle<JSObject> details; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, details, MaterializeScopeDetails(isolate, &it)); + return *details; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeCount) { +// Return an array of scope details +// args[0]: number: break id +// args[1]: number: frame index +// args[2]: number: inlined frame index +// args[3]: boolean: ignore nested scopes +// +// The array returned contains arrays with the following information: +// 0: Scope type +// 1: Scope object +RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) { + HandleScope scope(isolate); + ASSERT(args.length() == 3 || args.length() == 4); + CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); + RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); + + CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); + CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); + + bool ignore_nested_scopes = false; + if (args.length() == 4) { + CONVERT_BOOLEAN_ARG_CHECKED(flag, 3); + ignore_nested_scopes = flag; + } + + // Get the frame where the debugging is performed. + StackFrame::Id id = UnwrapFrameId(wrapped_id); + JavaScriptFrameIterator frame_it(isolate, id); + JavaScriptFrame* frame = frame_it.frame(); + + List<Handle<JSObject> > result(4); + ScopeIterator it(isolate, frame, inlined_jsframe_index, ignore_nested_scopes); + for (; !it.Done(); it.Next()) { + Handle<JSObject> details; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, details, MaterializeScopeDetails(isolate, &it)); + result.Add(details); + } + + Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length()); + for (int i = 0; i < result.length(); ++i) { + array->set(i, *result[i]); + } + return *isolate->factory()->NewJSArrayWithElements(array); +} + + +RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -12327,7 +12492,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeCount) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeDetails) { +RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) { HandleScope scope(isolate); ASSERT(args.length() == 2); @@ -12345,7 +12510,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeDetails) { return isolate->heap()->undefined_value(); } - return MaterializeScopeDetails(isolate, &it); + Handle<JSObject> details; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, details, MaterializeScopeDetails(isolate, &it)); + return *details; } @@ -12371,22 +12539,20 @@ static bool SetScopeVariableValue(ScopeIterator* it, int index, // args[5]: object: new value // // Return true if success and false otherwise -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScopeVariableValue) { +RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) { HandleScope scope(isolate); ASSERT(args.length() == 6); // Check arguments. CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4); - Handle<Object> new_value = args.at<Object>(5); + CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 5); bool res; if (args[0]->IsNumber()) { - Object* check; - { MaybeObject* maybe_check = Runtime_CheckExecutionState( - RUNTIME_ARGUMENTS(isolate, args)); - if (!maybe_check->ToObject(&check)) return maybe_check; - } + CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); + RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); + CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); @@ -12407,7 +12573,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScopeVariableValue) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) { +RUNTIME_FUNCTION(Runtime_DebugPrintScopes) { HandleScope scope(isolate); ASSERT(args.length() == 0); @@ -12425,16 +12591,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) { +RUNTIME_FUNCTION(Runtime_GetThreadCount) { HandleScope scope(isolate); ASSERT(args.length() == 1); - - // Check arguments. - Object* result; - { MaybeObject* maybe_result = Runtime_CheckExecutionState( - RUNTIME_ARGUMENTS(isolate, args)); - if (!maybe_result->ToObject(&result)) return maybe_result; - } + CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); + RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); // Count all archived V8 threads. int n = 0; @@ -12461,16 +12622,12 @@ static const int kThreadDetailsSize = 2; // The array returned contains the following information: // 0: Is current thread? // 1: Thread id -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) { +RUNTIME_FUNCTION(Runtime_GetThreadDetails) { HandleScope scope(isolate); ASSERT(args.length() == 2); + CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); + RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); - // Check arguments. - Object* check; - { MaybeObject* maybe_check = Runtime_CheckExecutionState( - RUNTIME_ARGUMENTS(isolate, args)); - if (!maybe_check->ToObject(&check)) return maybe_check; - } CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); // Allocate array for result. @@ -12511,7 +12668,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) { // Sets the disable break state // args[0]: disable break state -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) { +RUNTIME_FUNCTION(Runtime_SetDisableBreak) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0); @@ -12525,7 +12682,7 @@ static bool IsPositionAlignmentCodeCorrect(int alignment) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) { +RUNTIME_FUNCTION(Runtime_GetBreakLocations) { HandleScope scope(isolate); ASSERT(args.length() == 2); @@ -12553,17 +12710,18 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) { // args[0]: function // args[1]: number: break source position (within the function source) // args[2]: number: break point object -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) { +RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) { HandleScope scope(isolate); ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); - RUNTIME_ASSERT(source_position >= 0); - Handle<Object> break_point_object_arg = args.at<Object>(2); + RUNTIME_ASSERT(source_position >= function->shared()->start_position() && + source_position <= function->shared()->end_position()); + CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2); // Set break point. - isolate->debug()->SetBreakPoint(function, break_point_object_arg, - &source_position); + RUNTIME_ASSERT(isolate->debug()->SetBreakPoint( + function, break_point_object_arg, &source_position)); return Smi::FromInt(source_position); } @@ -12576,14 +12734,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) { // args[1]: number: break source position (within the script source) // args[2]: number, breakpoint position alignment // args[3]: number: break point object -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) { +RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) { HandleScope scope(isolate); ASSERT(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0); CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); RUNTIME_ASSERT(source_position >= 0); CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]); - Handle<Object> break_point_object_arg = args.at<Object>(3); + CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 3); if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) { return isolate->ThrowIllegalOperation(); @@ -12599,7 +12757,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) { if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg, &source_position, alignment)) { - return isolate->heap()->undefined_value(); + return isolate->heap()->undefined_value(); } return Smi::FromInt(source_position); @@ -12608,10 +12766,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) { // Clear a break point // args[0]: number: break point object -RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) { +RUNTIME_FUNCTION(Runtime_ClearBreakPoint) { HandleScope scope(isolate); ASSERT(args.length() == 1); - Handle<Object> break_point_object_arg = args.at<Object>(0); + CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0); // Clear break point. isolate->debug()->ClearBreakPoint(break_point_object_arg); @@ -12623,16 +12781,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) { // Change the state of break on exceptions. // args[0]: Enum value indicating whether to affect caught/uncaught exceptions. // args[1]: Boolean indicating on/off. -RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) { +RUNTIME_FUNCTION(Runtime_ChangeBreakOnException) { HandleScope scope(isolate); ASSERT(args.length() == 2); - RUNTIME_ASSERT(args[0]->IsNumber()); + CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]); CONVERT_BOOLEAN_ARG_CHECKED(enable, 1); // If the number doesn't match an enum value, the ChangeBreakOnException // function will default to affecting caught exceptions. - ExceptionBreakType type = - static_cast<ExceptionBreakType>(NumberToUint32(args[0])); + ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg); // Update break point state. isolate->debug()->ChangeBreakOnException(type, enable); return isolate->heap()->undefined_value(); @@ -12641,13 +12798,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) { // Returns the state of break on exceptions // args[0]: boolean indicating uncaught exceptions -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) { +RUNTIME_FUNCTION(Runtime_IsBreakOnException) { HandleScope scope(isolate); ASSERT(args.length() == 1); - RUNTIME_ASSERT(args[0]->IsNumber()); + CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]); - ExceptionBreakType type = - static_cast<ExceptionBreakType>(NumberToUint32(args[0])); + ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg); bool result = isolate->debug()->IsBreakOnException(type); return Smi::FromInt(result); } @@ -12658,15 +12814,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) { // args[1]: step action from the enumeration StepAction // args[2]: number of times to perform the step, for step out it is the number // of frames to step down. -RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) { +RUNTIME_FUNCTION(Runtime_PrepareStep) { HandleScope scope(isolate); ASSERT(args.length() == 4); - // Check arguments. - Object* check; - { MaybeObject* maybe_check = Runtime_CheckExecutionState( - RUNTIME_ARGUMENTS(isolate, args)); - if (!maybe_check->ToObject(&check)) return maybe_check; - } + CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); + RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); + if (!args[1]->IsNumber() || !args[2]->IsNumber()) { return isolate->Throw(isolate->heap()->illegal_argument_string()); } @@ -12713,7 +12866,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) { // Clear all stepping set by PrepareStep. -RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) { +RUNTIME_FUNCTION(Runtime_ClearStepping) { HandleScope scope(isolate); ASSERT(args.length() == 0); isolate->debug()->ClearStepping(); @@ -12723,59 +12876,58 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) { // Helper function to find or create the arguments object for // Runtime_DebugEvaluate. -static Handle<JSObject> MaterializeArgumentsObject( +MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeArgumentsObject( Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function) { // Do not materialize the arguments object for eval or top-level code. // Skip if "arguments" is already taken. if (!function->shared()->is_function() || - JSReceiver::HasLocalProperty(target, - isolate->factory()->arguments_string())) { + JSReceiver::HasOwnProperty( + target, isolate->factory()->arguments_string())) { return target; } // FunctionGetArguments can't throw an exception. Handle<JSObject> arguments = Handle<JSObject>::cast( Accessors::FunctionGetArguments(function)); - Runtime::SetObjectProperty(isolate, target, - isolate->factory()->arguments_string(), - arguments, - ::NONE, - kNonStrictMode); + Handle<String> arguments_str = isolate->factory()->arguments_string(); + RETURN_ON_EXCEPTION( + isolate, + Runtime::SetObjectProperty( + isolate, target, arguments_str, arguments, ::NONE, SLOPPY), + JSObject); return target; } // Compile and evaluate source for the given context. -static MaybeObject* DebugEvaluate(Isolate* isolate, - Handle<Context> context, - Handle<Object> context_extension, - Handle<Object> receiver, - Handle<String> source) { +static MaybeHandle<Object> DebugEvaluate(Isolate* isolate, + Handle<Context> context, + Handle<Object> context_extension, + Handle<Object> receiver, + Handle<String> source) { if (context_extension->IsJSObject()) { Handle<JSObject> extension = Handle<JSObject>::cast(context_extension); Handle<JSFunction> closure(context->closure(), isolate); context = isolate->factory()->NewWithContext(closure, context, extension); } - Handle<SharedFunctionInfo> shared = Compiler::CompileEval( - source, - context, - context->IsNativeContext(), - CLASSIC_MODE, - NO_PARSE_RESTRICTION, - RelocInfo::kNoPosition); - RETURN_IF_EMPTY_HANDLE(isolate, shared); - - Handle<JSFunction> eval_fun = - isolate->factory()->NewFunctionFromSharedFunctionInfo( - shared, context, NOT_TENURED); - bool pending_exception; - Handle<Object> result = Execution::Call( - isolate, eval_fun, receiver, 0, NULL, &pending_exception); + Handle<JSFunction> eval_fun; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, eval_fun, + Compiler::GetFunctionFromEval(source, + context, + SLOPPY, + NO_PARSE_RESTRICTION, + RelocInfo::kNoPosition), + Object); - if (pending_exception) return Failure::Exception(); + Handle<Object> result; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, result, + Execution::Call(isolate, eval_fun, receiver, 0, NULL), + Object); // Skip the global proxy as it has no properties and always delegates to the // real global object. @@ -12785,7 +12937,7 @@ static MaybeObject* DebugEvaluate(Isolate* isolate, // Clear the oneshot breakpoints so that the debugger does not step further. isolate->debug()->ClearStepping(); - return *result; + return result; } @@ -12794,25 +12946,23 @@ static MaybeObject* DebugEvaluate(Isolate* isolate, // - Parameters and stack-allocated locals need to be materialized. Altered // values need to be written back to the stack afterwards. // - The arguments object needs to materialized. -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { +RUNTIME_FUNCTION(Runtime_DebugEvaluate) { HandleScope scope(isolate); // Check the execution state and decode arguments frame and source to be // evaluated. ASSERT(args.length() == 6); - Object* check_result; - { MaybeObject* maybe_result = Runtime_CheckExecutionState( - RUNTIME_ARGUMENTS(isolate, args)); - if (!maybe_result->ToObject(&check_result)) return maybe_result; - } + CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); + RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); + CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); CONVERT_ARG_HANDLE_CHECKED(String, source, 3); CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4); - Handle<Object> context_extension(args[5], isolate); + CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 5); // Handle the processing of break. - DisableBreak disable_break_save(isolate, disable_break); + DisableBreak disable_break_scope(isolate->debug(), disable_break); // Get the frame where the debugging is performed. StackFrame::Id id = UnwrapFrameId(wrapped_id); @@ -12836,24 +12986,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { Handle<JSObject> materialized = isolate->factory()->NewJSObject(isolate->object_function()); - materialized = MaterializeStackLocalsWithFrameInspector( - isolate, materialized, function, &frame_inspector); - RETURN_IF_EMPTY_HANDLE(isolate, materialized); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, materialized, + MaterializeStackLocalsWithFrameInspector( + isolate, materialized, function, &frame_inspector)); - materialized = MaterializeArgumentsObject(isolate, materialized, function); - RETURN_IF_EMPTY_HANDLE(isolate, materialized); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, materialized, + MaterializeArgumentsObject(isolate, materialized, function)); // Add the materialized object in a with-scope to shadow the stack locals. context = isolate->factory()->NewWithContext(function, context, materialized); Handle<Object> receiver(frame->receiver(), isolate); - Object* evaluate_result_object; - { MaybeObject* maybe_result = - DebugEvaluate(isolate, context, context_extension, receiver, source); - if (!maybe_result->ToObject(&evaluate_result_object)) return maybe_result; - } - - Handle<Object> result(evaluate_result_object, isolate); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + DebugEvaluate(isolate, context, context_extension, receiver, source)); // Write back potential changes to materialized stack locals to the stack. UpdateStackLocalsFromMaterializedObject( @@ -12863,23 +13012,21 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) { +RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) { HandleScope scope(isolate); // Check the execution state and decode arguments frame and source to be // evaluated. ASSERT(args.length() == 4); - Object* check_result; - { MaybeObject* maybe_result = Runtime_CheckExecutionState( - RUNTIME_ARGUMENTS(isolate, args)); - if (!maybe_result->ToObject(&check_result)) return maybe_result; - } + CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); + RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); + CONVERT_ARG_HANDLE_CHECKED(String, source, 1); CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2); - Handle<Object> context_extension(args[3], isolate); + CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 3); // Handle the processing of break. - DisableBreak disable_break_save(isolate, disable_break); + DisableBreak disable_break_scope(isolate->debug(), disable_break); // Enter the top context from before the debugger was invoked. SaveContext save(isolate); @@ -12895,11 +13042,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) { // debugger was invoked. Handle<Context> context = isolate->native_context(); Handle<Object> receiver = isolate->global_object(); - return DebugEvaluate(isolate, context, context_extension, receiver, source); + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + DebugEvaluate(isolate, context, context_extension, receiver, source)); + return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) { +RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) { HandleScope scope(isolate); ASSERT(args.length() == 0); @@ -12914,14 +13065,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) { // instances->set(i, *GetScriptWrapper(script)) // is unsafe as GetScriptWrapper might call GC and the C++ compiler might // already have dereferenced the instances handle. - Handle<JSValue> wrapper = GetScriptWrapper(script); + Handle<JSObject> wrapper = Script::GetWrapper(script); instances->set(i, *wrapper); } // Return result as a JS array. Handle<JSObject> result = isolate->factory()->NewJSObject(isolate->array_function()); - isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances); + JSArray::SetContent(Handle<JSArray>::cast(result), instances); return *result; } @@ -13001,21 +13152,13 @@ static int DebugReferencedBy(HeapIterator* iterator, // args[0]: the object to find references to // args[1]: constructor function for instances to exclude (Mirror) // args[2]: the the maximum number of objects to return -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_DebugReferencedBy) { + HandleScope scope(isolate); ASSERT(args.length() == 3); - // First perform a full GC in order to avoid references from dead objects. - isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask, - "%DebugReferencedBy"); - // The heap iterator reserves the right to do a GC to make the heap iterable. - // Due to the GC above we know it won't need to do that, but it seems cleaner - // to get the heap iterator constructed before we start having unprotected - // Object* locals that are not protected by handles. - // Check parameters. - CONVERT_ARG_CHECKED(JSObject, target, 0); - Object* instance_filter = args[1]; + CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0); + CONVERT_ARG_HANDLE_CHECKED(Object, instance_filter, 1); RUNTIME_ASSERT(instance_filter->IsUndefined() || instance_filter->IsJSObject()); CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]); @@ -13023,40 +13166,42 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) { // Get the constructor function for context extension and arguments array. - JSObject* arguments_boilerplate = - isolate->context()->native_context()->arguments_boilerplate(); - JSFunction* arguments_function = - JSFunction::cast(arguments_boilerplate->map()->constructor()); + Handle<JSObject> arguments_boilerplate( + isolate->context()->native_context()->sloppy_arguments_boilerplate()); + Handle<JSFunction> arguments_function( + JSFunction::cast(arguments_boilerplate->map()->constructor())); // Get the number of referencing objects. int count; + // First perform a full GC in order to avoid dead objects and to make the heap + // iterable. Heap* heap = isolate->heap(); - HeapIterator heap_iterator(heap); - count = DebugReferencedBy(&heap_iterator, - target, instance_filter, max_references, - NULL, 0, arguments_function); + heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy"); + { + HeapIterator heap_iterator(heap); + count = DebugReferencedBy(&heap_iterator, + *target, *instance_filter, max_references, + NULL, 0, *arguments_function); + } // Allocate an array to hold the result. - Object* object; - { MaybeObject* maybe_object = heap->AllocateFixedArray(count); - if (!maybe_object->ToObject(&object)) return maybe_object; - } - FixedArray* instances = FixedArray::cast(object); + Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count); // Fill the referencing objects. - // AllocateFixedArray above does not make the heap non-iterable. - ASSERT(heap->IsHeapIterable()); - HeapIterator heap_iterator2(heap); - count = DebugReferencedBy(&heap_iterator2, - target, instance_filter, max_references, - instances, count, arguments_function); + { + HeapIterator heap_iterator(heap); + count = DebugReferencedBy(&heap_iterator, + *target, *instance_filter, max_references, + *instances, count, *arguments_function); + } // Return result as JS array. - Object* result; - MaybeObject* maybe_result = heap->AllocateJSObject( + Handle<JSFunction> constructor( isolate->context()->native_context()->array_function()); - if (!maybe_result->ToObject(&result)) return maybe_result; - return JSArray::cast(result)->SetContent(instances); + + Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); + JSArray::SetContent(Handle<JSArray>::cast(result), instances); + return *result; } @@ -13095,66 +13240,65 @@ static int DebugConstructedBy(HeapIterator* iterator, // Scan the heap for objects constructed by a specific function. // args[0]: the constructor to find instances of // args[1]: the the maximum number of objects to return -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_DebugConstructedBy) { + HandleScope scope(isolate); ASSERT(args.length() == 2); - // First perform a full GC in order to avoid dead objects. - Heap* heap = isolate->heap(); - heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy"); // Check parameters. - CONVERT_ARG_CHECKED(JSFunction, constructor, 0); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0); CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]); RUNTIME_ASSERT(max_references >= 0); // Get the number of referencing objects. int count; - HeapIterator heap_iterator(heap); - count = DebugConstructedBy(&heap_iterator, - constructor, - max_references, - NULL, - 0); + // First perform a full GC in order to avoid dead objects and to make the heap + // iterable. + Heap* heap = isolate->heap(); + heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy"); + { + HeapIterator heap_iterator(heap); + count = DebugConstructedBy(&heap_iterator, + *constructor, + max_references, + NULL, + 0); + } // Allocate an array to hold the result. - Object* object; - { MaybeObject* maybe_object = heap->AllocateFixedArray(count); - if (!maybe_object->ToObject(&object)) return maybe_object; - } - FixedArray* instances = FixedArray::cast(object); + Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count); - ASSERT(isolate->heap()->IsHeapIterable()); // Fill the referencing objects. - HeapIterator heap_iterator2(heap); - count = DebugConstructedBy(&heap_iterator2, - constructor, - max_references, - instances, - count); + { + HeapIterator heap_iterator2(heap); + count = DebugConstructedBy(&heap_iterator2, + *constructor, + max_references, + *instances, + count); + } // Return result as JS array. - Object* result; - { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject( + Handle<JSFunction> array_function( isolate->context()->native_context()->array_function()); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - return JSArray::cast(result)->SetContent(instances); + Handle<JSObject> result = isolate->factory()->NewJSObject(array_function); + JSArray::SetContent(Handle<JSArray>::cast(result), instances); + return *result; } // Find the effective prototype object as returned by __proto__. // args[0]: the object to find the prototype for. -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_DebugGetPrototype) { + HandleScope shs(isolate); ASSERT(args.length() == 1); - CONVERT_ARG_CHECKED(JSObject, obj, 0); - return GetPrototypeSkipHiddenPrototypes(isolate, obj); + CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); + return *GetPrototypeSkipHiddenPrototypes(isolate, obj); } // Patches script source (should be called upon BeforeCompile event). -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) { +RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) { HandleScope scope(isolate); ASSERT(args.length() == 2); @@ -13172,7 +13316,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) { +RUNTIME_FUNCTION(Runtime_SystemBreak) { SealHandleScope shs(isolate); ASSERT(args.length() == 0); OS::DebugBreak(); @@ -13180,14 +13324,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) { +RUNTIME_FUNCTION(Runtime_DebugDisassembleFunction) { HandleScope scope(isolate); #ifdef DEBUG ASSERT(args.length() == 1); // Get the function and make sure it is compiled. CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); - if (!JSFunction::EnsureCompiled(func, KEEP_EXCEPTION)) { - return Failure::Exception(); + if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) { + return isolate->heap()->exception(); } func->code()->PrintLn(); #endif // DEBUG @@ -13195,14 +13339,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) { +RUNTIME_FUNCTION(Runtime_DebugDisassembleConstructor) { HandleScope scope(isolate); #ifdef DEBUG ASSERT(args.length() == 1); // Get the function and make sure it is compiled. CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); - if (!JSFunction::EnsureCompiled(func, KEEP_EXCEPTION)) { - return Failure::Exception(); + if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) { + return isolate->heap()->exception(); } func->shared()->construct_stub()->PrintLn(); #endif // DEBUG @@ -13210,7 +13354,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) { +RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); @@ -13248,10 +13392,9 @@ static int FindSharedFunctionInfosForScript(HeapIterator* iterator, // For a script finds all SharedFunctionInfo's in the heap that points // to this script. Returns JSArray of SharedFunctionInfo wrapped // in OpaqueReferences. -RUNTIME_FUNCTION(MaybeObject*, - Runtime_LiveEditFindSharedFunctionInfosForScript) { +RUNTIME_FUNCTION(Runtime_LiveEditFindSharedFunctionInfosForScript) { HandleScope scope(isolate); - CHECK(isolate->debugger()->live_edit_enabled()); + CHECK(isolate->debug()->live_edit_enabled()); ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSValue, script_value, 0); @@ -13265,8 +13408,6 @@ RUNTIME_FUNCTION(MaybeObject*, int number; Heap* heap = isolate->heap(); { - heap->EnsureHeapIsIterable(); - DisallowHeapAllocation no_allocation; HeapIterator heap_iterator(heap); Script* scr = *script; FixedArray* arr = *array; @@ -13274,8 +13415,6 @@ RUNTIME_FUNCTION(MaybeObject*, } if (number > kBufferSize) { array = isolate->factory()->NewFixedArray(number); - heap->EnsureHeapIsIterable(); - DisallowHeapAllocation no_allocation; HeapIterator heap_iterator(heap); Script* scr = *script; FixedArray* arr = *array; @@ -13298,9 +13437,9 @@ RUNTIME_FUNCTION(MaybeObject*, // Returns a JSArray of compilation infos. The array is ordered so that // each function with all its descendant is always stored in a continues range // with the function itself going first. The root function is a script function. -RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) { +RUNTIME_FUNCTION(Runtime_LiveEditGatherCompileInfo) { HandleScope scope(isolate); - CHECK(isolate->debugger()->live_edit_enabled()); + CHECK(isolate->debug()->live_edit_enabled()); ASSERT(args.length() == 2); CONVERT_ARG_CHECKED(JSValue, script, 0); CONVERT_ARG_HANDLE_CHECKED(String, source, 1); @@ -13308,71 +13447,72 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) { RUNTIME_ASSERT(script->value()->IsScript()); Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); - JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source); - - if (isolate->has_pending_exception()) { - return Failure::Exception(); - } - - return result; + Handle<JSArray> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, LiveEdit::GatherCompileInfo(script_handle, source)); + return *result; } // Changes the source of the script to a new_source. // If old_script_name is provided (i.e. is a String), also creates a copy of // the script with its original source and sends notification to debugger. -RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) { +RUNTIME_FUNCTION(Runtime_LiveEditReplaceScript) { HandleScope scope(isolate); - CHECK(isolate->debugger()->live_edit_enabled()); + CHECK(isolate->debug()->live_edit_enabled()); ASSERT(args.length() == 3); CONVERT_ARG_CHECKED(JSValue, original_script_value, 0); CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1); - Handle<Object> old_script_name(args[2], isolate); + CONVERT_ARG_HANDLE_CHECKED(Object, old_script_name, 2); RUNTIME_ASSERT(original_script_value->value()->IsScript()); Handle<Script> original_script(Script::cast(original_script_value->value())); - Object* old_script = LiveEdit::ChangeScriptSource(original_script, - new_source, - old_script_name); + Handle<Object> old_script = LiveEdit::ChangeScriptSource( + original_script, new_source, old_script_name); if (old_script->IsScript()) { - Handle<Script> script_handle(Script::cast(old_script)); - return *(GetScriptWrapper(script_handle)); + Handle<Script> script_handle = Handle<Script>::cast(old_script); + return *Script::GetWrapper(script_handle); } else { return isolate->heap()->null_value(); } } -RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) { +RUNTIME_FUNCTION(Runtime_LiveEditFunctionSourceUpdated) { HandleScope scope(isolate); - CHECK(isolate->debugger()->live_edit_enabled()); + CHECK(isolate->debug()->live_edit_enabled()); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0); - return LiveEdit::FunctionSourceUpdated(shared_info); + RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info)); + + LiveEdit::FunctionSourceUpdated(shared_info); + return isolate->heap()->undefined_value(); } // Replaces code of SharedFunctionInfo with a new one. -RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) { +RUNTIME_FUNCTION(Runtime_LiveEditReplaceFunctionCode) { HandleScope scope(isolate); - CHECK(isolate->debugger()->live_edit_enabled()); + CHECK(isolate->debug()->live_edit_enabled()); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0); CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1); + RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info)); - return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info); + LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info); + return isolate->heap()->undefined_value(); } // Connects SharedFunctionInfo to another script. -RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) { +RUNTIME_FUNCTION(Runtime_LiveEditFunctionSetScript) { HandleScope scope(isolate); - CHECK(isolate->debugger()->live_edit_enabled()); + CHECK(isolate->debug()->live_edit_enabled()); ASSERT(args.length() == 2); - Handle<Object> function_object(args[0], isolate); - Handle<Object> script_object(args[1], isolate); + CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0); + CONVERT_ARG_HANDLE_CHECKED(Object, script_object, 1); if (function_object->IsJSValue()) { Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object); @@ -13381,7 +13521,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) { Script* script = Script::cast(JSValue::cast(*script_object)->value()); script_object = Handle<Object>(script, isolate); } - + RUNTIME_ASSERT(function_wrapper->value()->IsSharedFunctionInfo()); LiveEdit::SetFunctionScript(function_wrapper, script_object); } else { // Just ignore this. We may not have a SharedFunctionInfo for some functions @@ -13394,18 +13534,20 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) { // In a code of a parent function replaces original function as embedded object // with a substitution one. -RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) { +RUNTIME_FUNCTION(Runtime_LiveEditReplaceRefToNestedFunction) { HandleScope scope(isolate); - CHECK(isolate->debugger()->live_edit_enabled()); + CHECK(isolate->debug()->live_edit_enabled()); ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0); CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1); CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2); + RUNTIME_ASSERT(parent_wrapper->value()->IsSharedFunctionInfo()); + RUNTIME_ASSERT(orig_wrapper->value()->IsSharedFunctionInfo()); + RUNTIME_ASSERT(subst_wrapper->value()->IsSharedFunctionInfo()); - LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper, - subst_wrapper); - + LiveEdit::ReplaceRefToNestedFunction( + parent_wrapper, orig_wrapper, subst_wrapper); return isolate->heap()->undefined_value(); } @@ -13415,14 +13557,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) { // array of groups of 3 numbers: // (change_begin, change_end, change_end_new_position). // Each group describes a change in text; groups are sorted by change_begin. -RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) { +RUNTIME_FUNCTION(Runtime_LiveEditPatchFunctionPositions) { HandleScope scope(isolate); - CHECK(isolate->debugger()->live_edit_enabled()); + CHECK(isolate->debug()->live_edit_enabled()); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0); CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1); + RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_array)) - return LiveEdit::PatchFunctionPositions(shared_array, position_change_array); + LiveEdit::PatchFunctionPositions(shared_array, position_change_array); + return isolate->heap()->undefined_value(); } @@ -13430,12 +13574,21 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) { // checks that none of them have activations on stacks (of any thread). // Returns array of the same length with corresponding results of // LiveEdit::FunctionPatchabilityStatus type. -RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) { +RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) { HandleScope scope(isolate); - CHECK(isolate->debugger()->live_edit_enabled()); + CHECK(isolate->debug()->live_edit_enabled()); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0); CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1); + RUNTIME_ASSERT(shared_array->length()->IsSmi()); + int array_length = Smi::cast(shared_array->length())->value(); + for (int i = 0; i < array_length; i++) { + Handle<Object> element = + Object::GetElement(isolate, shared_array, i).ToHandleChecked(); + RUNTIME_ASSERT( + element->IsJSValue() && + Handle<JSValue>::cast(element)->value()->IsSharedFunctionInfo()); + } return *LiveEdit::CheckAndDropActivations(shared_array, do_drop); } @@ -13444,9 +13597,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) { // Compares 2 strings line-by-line, then token-wise and returns diff in form // of JSArray of triplets (pos1, pos1_end, pos2_end) describing list // of diff chunks. -RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) { +RUNTIME_FUNCTION(Runtime_LiveEditCompareStrings) { HandleScope scope(isolate); - CHECK(isolate->debugger()->live_edit_enabled()); + CHECK(isolate->debug()->live_edit_enabled()); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(String, s1, 0); CONVERT_ARG_HANDLE_CHECKED(String, s2, 1); @@ -13457,17 +13610,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) { // Restarts a call frame and completely drops all frames above. // Returns true if successful. Otherwise returns undefined or an error message. -RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditRestartFrame) { +RUNTIME_FUNCTION(Runtime_LiveEditRestartFrame) { HandleScope scope(isolate); - CHECK(isolate->debugger()->live_edit_enabled()); + CHECK(isolate->debug()->live_edit_enabled()); ASSERT(args.length() == 2); + CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); + RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); - // Check arguments. - Object* check; - { MaybeObject* maybe_check = Runtime_CheckExecutionState( - RUNTIME_ARGUMENTS(isolate, args)); - if (!maybe_check->ToObject(&check)) return maybe_check; - } CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); Heap* heap = isolate->heap(); @@ -13496,9 +13645,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditRestartFrame) { // A testing entry. Returns statement position which is the closest to // source_position. -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) { +RUNTIME_FUNCTION(Runtime_GetFunctionCodePositionFromSource) { HandleScope scope(isolate); - CHECK(isolate->debugger()->live_edit_enabled()); + CHECK(isolate->debug()->live_edit_enabled()); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); @@ -13534,63 +13683,59 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) { // Calls specified function with or without entering the debugger. // This is used in unit tests to run code as if debugger is entered or simply // to have a stack with C++ frame in the middle. -RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) { +RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext) { HandleScope scope(isolate); ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1); - Handle<Object> result; - bool pending_exception; - { - if (without_debugger) { - result = Execution::Call(isolate, - function, - isolate->global_object(), - 0, - NULL, - &pending_exception); - } else { - EnterDebugger enter_debugger(isolate); - result = Execution::Call(isolate, - function, - isolate->global_object(), - 0, - NULL, - &pending_exception); - } - } - if (!pending_exception) { - return *result; + MaybeHandle<Object> maybe_result; + if (without_debugger) { + maybe_result = Execution::Call(isolate, + function, + isolate->global_object(), + 0, + NULL); } else { - return Failure::Exception(); + DebugScope debug_scope(isolate->debug()); + maybe_result = Execution::Call(isolate, + function, + isolate->global_object(), + 0, + NULL); } + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result); + return *result; } // Sets a v8 flag. -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) { +RUNTIME_FUNCTION(Runtime_SetFlags) { SealHandleScope shs(isolate); + ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(String, arg, 0); SmartArrayPointer<char> flags = arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); - FlagList::SetFlagsFromString(*flags, StrLength(*flags)); + FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get())); return isolate->heap()->undefined_value(); } // Performs a GC. // Presently, it only does a full GC. -RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) { +RUNTIME_FUNCTION(Runtime_CollectGarbage) { SealHandleScope shs(isolate); + ASSERT(args.length() == 1); isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage"); return isolate->heap()->undefined_value(); } // Gets the current heap usage. -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) { +RUNTIME_FUNCTION(Runtime_GetHeapUsage) { SealHandleScope shs(isolate); + ASSERT(args.length() == 0); int usage = static_cast<int>(isolate->heap()->SizeOfObjects()); if (!Smi::IsValid(usage)) { return *isolate->factory()->NewNumberFromInt(usage); @@ -13598,12 +13743,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) { return Smi::FromInt(usage); } -#endif // ENABLE_DEBUGGER_SUPPORT - #ifdef V8_I18N_SUPPORT -RUNTIME_FUNCTION(MaybeObject*, Runtime_CanonicalizeLanguageTag) { +RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) { HandleScope scope(isolate); + Factory* factory = isolate->factory(); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0); @@ -13620,7 +13764,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CanonicalizeLanguageTag) { uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY, &icu_length, &error); if (U_FAILURE(error) || icu_length == 0) { - return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag)); + return *factory->NewStringFromAsciiChecked(kInvalidTag); } char result[ULOC_FULLNAME_CAPACITY]; @@ -13629,15 +13773,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CanonicalizeLanguageTag) { uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error); if (U_FAILURE(error)) { - return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag)); + return *factory->NewStringFromAsciiChecked(kInvalidTag); } - return isolate->heap()->AllocateStringFromOneByte(CStrVector(result)); + return *factory->NewStringFromAsciiChecked(result); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_AvailableLocalesOf) { +RUNTIME_FUNCTION(Runtime_AvailableLocalesOf) { HandleScope scope(isolate); + Factory* factory = isolate->factory(); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(String, service, 0); @@ -13658,7 +13803,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_AvailableLocalesOf) { UErrorCode error = U_ZERO_ERROR; char result[ULOC_FULLNAME_CAPACITY]; Handle<JSObject> locales = - isolate->factory()->NewJSObject(isolate->object_function()); + factory->NewJSObject(isolate->object_function()); for (int32_t i = 0; i < count; ++i) { const char* icu_name = available_locales[i].getName(); @@ -13671,11 +13816,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_AvailableLocalesOf) { continue; } - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::SetLocalPropertyIgnoreAttributes( + RETURN_FAILURE_ON_EXCEPTION(isolate, + JSObject::SetOwnPropertyIgnoreAttributes( locales, - isolate->factory()->NewStringFromAscii(CStrVector(result)), - isolate->factory()->NewNumber(i), + factory->NewStringFromAsciiChecked(result), + factory->NewNumber(i), NONE)); } @@ -13683,8 +13828,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_AvailableLocalesOf) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultICULocale) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_GetDefaultICULocale) { + HandleScope scope(isolate); + Factory* factory = isolate->factory(); ASSERT(args.length() == 0); @@ -13696,35 +13842,38 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultICULocale) { uloc_toLanguageTag( default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); if (U_SUCCESS(status)) { - return isolate->heap()->AllocateStringFromOneByte(CStrVector(result)); + return *factory->NewStringFromAsciiChecked(result); } - return isolate->heap()->AllocateStringFromOneByte(CStrVector("und")); + return *factory->NewStringFromStaticAscii("und"); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLanguageTagVariants) { +RUNTIME_FUNCTION(Runtime_GetLanguageTagVariants) { HandleScope scope(isolate); + Factory* factory = isolate->factory(); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0); uint32_t length = static_cast<uint32_t>(input->length()->Number()); - Handle<FixedArray> output = isolate->factory()->NewFixedArray(length); - Handle<Name> maximized = - isolate->factory()->NewStringFromAscii(CStrVector("maximized")); - Handle<Name> base = - isolate->factory()->NewStringFromAscii(CStrVector("base")); + // Set some limit to prevent fuzz tests from going OOM. + // Can be bumped when callers' requirements change. + RUNTIME_ASSERT(length < 100); + Handle<FixedArray> output = factory->NewFixedArray(length); + Handle<Name> maximized = factory->NewStringFromStaticAscii("maximized"); + Handle<Name> base = factory->NewStringFromStaticAscii("base"); for (unsigned int i = 0; i < length; ++i) { - MaybeObject* maybe_string = input->GetElement(isolate, i); - Object* locale_id; - if (!maybe_string->ToObject(&locale_id) || !locale_id->IsString()) { - return isolate->Throw(isolate->heap()->illegal_argument_string()); + Handle<Object> locale_id; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, locale_id, Object::GetElement(isolate, input, i)); + if (!locale_id->IsString()) { + return isolate->Throw(*factory->illegal_argument_string()); } v8::String::Utf8Value utf8_locale_id( - v8::Utils::ToLocal(Handle<String>(String::cast(locale_id)))); + v8::Utils::ToLocal(Handle<String>::cast(locale_id))); UErrorCode error = U_ZERO_ERROR; @@ -13735,7 +13884,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLanguageTagVariants) { uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY, &icu_locale_length, &error); if (U_FAILURE(error) || icu_locale_length == 0) { - return isolate->Throw(isolate->heap()->illegal_argument_string()); + return isolate->Throw(*factory->illegal_argument_string()); } // Maximize the locale. @@ -13768,33 +13917,113 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLanguageTagVariants) { icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error); if (U_FAILURE(error)) { - return isolate->Throw(isolate->heap()->illegal_argument_string()); + return isolate->Throw(*factory->illegal_argument_string()); } - Handle<JSObject> result = - isolate->factory()->NewJSObject(isolate->object_function()); - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::SetLocalPropertyIgnoreAttributes( + Handle<JSObject> result = factory->NewJSObject(isolate->object_function()); + RETURN_FAILURE_ON_EXCEPTION(isolate, + JSObject::SetOwnPropertyIgnoreAttributes( result, maximized, - isolate->factory()->NewStringFromAscii(CStrVector(base_max_locale)), + factory->NewStringFromAsciiChecked(base_max_locale), NONE)); - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::SetLocalPropertyIgnoreAttributes( + RETURN_FAILURE_ON_EXCEPTION(isolate, + JSObject::SetOwnPropertyIgnoreAttributes( result, base, - isolate->factory()->NewStringFromAscii(CStrVector(base_locale)), + factory->NewStringFromAsciiChecked(base_locale), NONE)); output->set(i, *result); } - Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(output); + Handle<JSArray> result = factory->NewJSArrayWithElements(output); result->set_length(Smi::FromInt(length)); return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateDateTimeFormat) { +RUNTIME_FUNCTION(Runtime_IsInitializedIntlObject) { + HandleScope scope(isolate); + + ASSERT(args.length() == 1); + + CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); + + if (!input->IsJSObject()) return isolate->heap()->false_value(); + Handle<JSObject> obj = Handle<JSObject>::cast(input); + + Handle<String> marker = isolate->factory()->intl_initialized_marker_string(); + Handle<Object> tag(obj->GetHiddenProperty(marker), isolate); + return isolate->heap()->ToBoolean(!tag->IsTheHole()); +} + + +RUNTIME_FUNCTION(Runtime_IsInitializedIntlObjectOfType) { + HandleScope scope(isolate); + + ASSERT(args.length() == 2); + + CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); + CONVERT_ARG_HANDLE_CHECKED(String, expected_type, 1); + + if (!input->IsJSObject()) return isolate->heap()->false_value(); + Handle<JSObject> obj = Handle<JSObject>::cast(input); + + Handle<String> marker = isolate->factory()->intl_initialized_marker_string(); + Handle<Object> tag(obj->GetHiddenProperty(marker), isolate); + return isolate->heap()->ToBoolean( + tag->IsString() && String::cast(*tag)->Equals(*expected_type)); +} + + +RUNTIME_FUNCTION(Runtime_MarkAsInitializedIntlObjectOfType) { + HandleScope scope(isolate); + + ASSERT(args.length() == 3); + + CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0); + CONVERT_ARG_HANDLE_CHECKED(String, type, 1); + CONVERT_ARG_HANDLE_CHECKED(JSObject, impl, 2); + + Handle<String> marker = isolate->factory()->intl_initialized_marker_string(); + JSObject::SetHiddenProperty(input, marker, type); + + marker = isolate->factory()->intl_impl_object_string(); + JSObject::SetHiddenProperty(input, marker, impl); + + return isolate->heap()->undefined_value(); +} + + +RUNTIME_FUNCTION(Runtime_GetImplFromInitializedIntlObject) { + HandleScope scope(isolate); + + ASSERT(args.length() == 1); + + CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); + + if (!input->IsJSObject()) { + Vector< Handle<Object> > arguments = HandleVector(&input, 1); + Handle<Object> type_error = + isolate->factory()->NewTypeError("not_intl_object", arguments); + return isolate->Throw(*type_error); + } + + Handle<JSObject> obj = Handle<JSObject>::cast(input); + + Handle<String> marker = isolate->factory()->intl_impl_object_string(); + Handle<Object> impl(obj->GetHiddenProperty(marker), isolate); + if (impl->IsTheHole()) { + Vector< Handle<Object> > arguments = HandleVector(&obj, 1); + Handle<Object> type_error = + isolate->factory()->NewTypeError("not_intl_object", arguments); + return isolate->Throw(*type_error); + } + return *impl; +} + + +RUNTIME_FUNCTION(Runtime_CreateDateTimeFormat) { HandleScope scope(isolate); ASSERT(args.length() == 3); @@ -13807,13 +14036,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateDateTimeFormat) { I18N::GetTemplate(isolate); // Create an empty object wrapper. - bool has_pending_exception = false; - Handle<JSObject> local_object = Execution::InstantiateObject( - date_format_template, &has_pending_exception); - if (has_pending_exception) { - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } + Handle<JSObject> local_object; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, local_object, + Execution::InstantiateObject(date_format_template)); // Set date time formatter as internal field of the resulting JS object. icu::SimpleDateFormat* date_format = DateFormat::InitializeDateTimeFormat( @@ -13823,23 +14049,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateDateTimeFormat) { local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format)); - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::SetLocalPropertyIgnoreAttributes( + RETURN_FAILURE_ON_EXCEPTION(isolate, + JSObject::SetOwnPropertyIgnoreAttributes( local_object, - isolate->factory()->NewStringFromAscii(CStrVector("dateFormat")), - isolate->factory()->NewStringFromAscii(CStrVector("valid")), + isolate->factory()->NewStringFromStaticAscii("dateFormat"), + isolate->factory()->NewStringFromStaticAscii("valid"), NONE)); // Make object handle weak so we can delete the data format once GC kicks in. Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); - GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()), - NULL, + GlobalHandles::MakeWeak(wrapper.location(), + reinterpret_cast<void*>(wrapper.location()), DateFormat::DeleteDateFormat); return *local_object; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateFormat) { +RUNTIME_FUNCTION(Runtime_InternalDateFormat) { HandleScope scope(isolate); ASSERT(args.length() == 2); @@ -13847,13 +14073,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateFormat) { CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0); CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1); - bool has_pending_exception = false; - Handle<Object> value = - Execution::ToNumber(isolate, date, &has_pending_exception); - if (has_pending_exception) { - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } + Handle<Object> value; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, value, Execution::ToNumber(isolate, date)); icu::SimpleDateFormat* date_format = DateFormat::UnpackDateFormat(isolate, date_format_holder); @@ -13862,14 +14084,18 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateFormat) { icu::UnicodeString result; date_format->format(value->Number(), result); - return *isolate->factory()->NewStringFromTwoByte( - Vector<const uint16_t>( - reinterpret_cast<const uint16_t*>(result.getBuffer()), - result.length())); + Handle<String> result_str; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result_str, + isolate->factory()->NewStringFromTwoByte( + Vector<const uint16_t>( + reinterpret_cast<const uint16_t*>(result.getBuffer()), + result.length()))); + return *result_str; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateParse) { +RUNTIME_FUNCTION(Runtime_InternalDateParse) { HandleScope scope(isolate); ASSERT(args.length() == 2); @@ -13887,19 +14113,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateParse) { UDate date = date_format->parse(u_date, status); if (U_FAILURE(status)) return isolate->heap()->undefined_value(); - bool has_pending_exception = false; - Handle<JSDate> result = Handle<JSDate>::cast( - Execution::NewDate( - isolate, static_cast<double>(date), &has_pending_exception)); - if (has_pending_exception) { - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } + Handle<Object> result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + Execution::NewDate(isolate, static_cast<double>(date))); + ASSERT(result->IsJSDate()); return *result; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateNumberFormat) { +RUNTIME_FUNCTION(Runtime_CreateNumberFormat) { HandleScope scope(isolate); ASSERT(args.length() == 3); @@ -13912,13 +14135,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateNumberFormat) { I18N::GetTemplate(isolate); // Create an empty object wrapper. - bool has_pending_exception = false; - Handle<JSObject> local_object = Execution::InstantiateObject( - number_format_template, &has_pending_exception); - if (has_pending_exception) { - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } + Handle<JSObject> local_object; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, local_object, + Execution::InstantiateObject(number_format_template)); // Set number formatter as internal field of the resulting JS object. icu::DecimalFormat* number_format = NumberFormat::InitializeNumberFormat( @@ -13928,22 +14148,22 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateNumberFormat) { local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format)); - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::SetLocalPropertyIgnoreAttributes( + RETURN_FAILURE_ON_EXCEPTION(isolate, + JSObject::SetOwnPropertyIgnoreAttributes( local_object, - isolate->factory()->NewStringFromAscii(CStrVector("numberFormat")), - isolate->factory()->NewStringFromAscii(CStrVector("valid")), + isolate->factory()->NewStringFromStaticAscii("numberFormat"), + isolate->factory()->NewStringFromStaticAscii("valid"), NONE)); Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); - GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()), - NULL, + GlobalHandles::MakeWeak(wrapper.location(), + reinterpret_cast<void*>(wrapper.location()), NumberFormat::DeleteNumberFormat); return *local_object; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberFormat) { +RUNTIME_FUNCTION(Runtime_InternalNumberFormat) { HandleScope scope(isolate); ASSERT(args.length() == 2); @@ -13951,13 +14171,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberFormat) { CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0); CONVERT_ARG_HANDLE_CHECKED(Object, number, 1); - bool has_pending_exception = false; - Handle<Object> value = Execution::ToNumber( - isolate, number, &has_pending_exception); - if (has_pending_exception) { - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } + Handle<Object> value; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, value, Execution::ToNumber(isolate, number)); icu::DecimalFormat* number_format = NumberFormat::UnpackNumberFormat(isolate, number_format_holder); @@ -13966,14 +14182,18 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberFormat) { icu::UnicodeString result; number_format->format(value->Number(), result); - return *isolate->factory()->NewStringFromTwoByte( - Vector<const uint16_t>( - reinterpret_cast<const uint16_t*>(result.getBuffer()), - result.length())); + Handle<String> result_str; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result_str, + isolate->factory()->NewStringFromTwoByte( + Vector<const uint16_t>( + reinterpret_cast<const uint16_t*>(result.getBuffer()), + result.length()))); + return *result_str; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberParse) { +RUNTIME_FUNCTION(Runtime_InternalNumberParse) { HandleScope scope(isolate); ASSERT(args.length() == 2); @@ -14012,7 +14232,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberParse) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCollator) { +RUNTIME_FUNCTION(Runtime_CreateCollator) { HandleScope scope(isolate); ASSERT(args.length() == 3); @@ -14024,13 +14244,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCollator) { Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate); // Create an empty object wrapper. - bool has_pending_exception = false; - Handle<JSObject> local_object = Execution::InstantiateObject( - collator_template, &has_pending_exception); - if (has_pending_exception) { - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } + Handle<JSObject> local_object; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, local_object, Execution::InstantiateObject(collator_template)); // Set collator as internal field of the resulting JS object. icu::Collator* collator = Collator::InitializeCollator( @@ -14040,22 +14256,22 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCollator) { local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator)); - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::SetLocalPropertyIgnoreAttributes( + RETURN_FAILURE_ON_EXCEPTION(isolate, + JSObject::SetOwnPropertyIgnoreAttributes( local_object, - isolate->factory()->NewStringFromAscii(CStrVector("collator")), - isolate->factory()->NewStringFromAscii(CStrVector("valid")), + isolate->factory()->NewStringFromStaticAscii("collator"), + isolate->factory()->NewStringFromStaticAscii("valid"), NONE)); Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); - GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()), - NULL, + GlobalHandles::MakeWeak(wrapper.location(), + reinterpret_cast<void*>(wrapper.location()), Collator::DeleteCollator); return *local_object; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalCompare) { +RUNTIME_FUNCTION(Runtime_InternalCompare) { HandleScope scope(isolate); ASSERT(args.length() == 3); @@ -14083,7 +14299,42 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalCompare) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateBreakIterator) { +RUNTIME_FUNCTION(Runtime_StringNormalize) { + HandleScope scope(isolate); + static const UNormalizationMode normalizationForms[] = + { UNORM_NFC, UNORM_NFD, UNORM_NFKC, UNORM_NFKD }; + + ASSERT(args.length() == 2); + + CONVERT_ARG_HANDLE_CHECKED(String, stringValue, 0); + CONVERT_NUMBER_CHECKED(int, form_id, Int32, args[1]); + RUNTIME_ASSERT(form_id >= 0 && + static_cast<size_t>(form_id) < ARRAY_SIZE(normalizationForms)); + + v8::String::Value string_value(v8::Utils::ToLocal(stringValue)); + const UChar* u_value = reinterpret_cast<const UChar*>(*string_value); + + // TODO(mnita): check Normalizer2 (not available in ICU 46) + UErrorCode status = U_ZERO_ERROR; + icu::UnicodeString result; + icu::Normalizer::normalize(u_value, normalizationForms[form_id], 0, + result, status); + if (U_FAILURE(status)) { + return isolate->heap()->undefined_value(); + } + + Handle<String> result_str; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result_str, + isolate->factory()->NewStringFromTwoByte( + Vector<const uint16_t>( + reinterpret_cast<const uint16_t*>(result.getBuffer()), + result.length()))); + return *result_str; +} + + +RUNTIME_FUNCTION(Runtime_CreateBreakIterator) { HandleScope scope(isolate); ASSERT(args.length() == 3); @@ -14096,13 +14347,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateBreakIterator) { I18N::GetTemplate2(isolate); // Create an empty object wrapper. - bool has_pending_exception = false; - Handle<JSObject> local_object = Execution::InstantiateObject( - break_iterator_template, &has_pending_exception); - if (has_pending_exception) { - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } + Handle<JSObject> local_object; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, local_object, + Execution::InstantiateObject(break_iterator_template)); // Set break iterator as internal field of the resulting JS object. icu::BreakIterator* break_iterator = BreakIterator::InitializeBreakIterator( @@ -14114,24 +14362,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateBreakIterator) { // Make sure that the pointer to adopted text is NULL. local_object->SetInternalField(1, reinterpret_cast<Smi*>(NULL)); - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::SetLocalPropertyIgnoreAttributes( + RETURN_FAILURE_ON_EXCEPTION(isolate, + JSObject::SetOwnPropertyIgnoreAttributes( local_object, - isolate->factory()->NewStringFromAscii(CStrVector("breakIterator")), - isolate->factory()->NewStringFromAscii(CStrVector("valid")), + isolate->factory()->NewStringFromStaticAscii("breakIterator"), + isolate->factory()->NewStringFromStaticAscii("valid"), NONE)); // Make object handle weak so we can delete the break iterator once GC kicks // in. Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); - GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()), - NULL, + GlobalHandles::MakeWeak(wrapper.location(), + reinterpret_cast<void*>(wrapper.location()), BreakIterator::DeleteBreakIterator); return *local_object; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorAdoptText) { +RUNTIME_FUNCTION(Runtime_BreakIteratorAdoptText) { HandleScope scope(isolate); ASSERT(args.length() == 2); @@ -14158,7 +14406,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorAdoptText) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorFirst) { +RUNTIME_FUNCTION(Runtime_BreakIteratorFirst) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -14173,7 +14421,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorFirst) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorNext) { +RUNTIME_FUNCTION(Runtime_BreakIteratorNext) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -14188,7 +14436,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorNext) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorCurrent) { +RUNTIME_FUNCTION(Runtime_BreakIteratorCurrent) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -14203,7 +14451,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorCurrent) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorBreakType) { +RUNTIME_FUNCTION(Runtime_BreakIteratorBreakType) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -14220,17 +14468,17 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorBreakType) { int32_t status = rule_based_iterator->getRuleStatus(); // Keep return values in sync with JavaScript BreakType enum. if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) { - return *isolate->factory()->NewStringFromAscii(CStrVector("none")); + return *isolate->factory()->NewStringFromStaticAscii("none"); } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) { - return *isolate->factory()->NewStringFromAscii(CStrVector("number")); + return *isolate->factory()->NewStringFromStaticAscii("number"); } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) { - return *isolate->factory()->NewStringFromAscii(CStrVector("letter")); + return *isolate->factory()->NewStringFromStaticAscii("letter"); } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) { - return *isolate->factory()->NewStringFromAscii(CStrVector("kana")); + return *isolate->factory()->NewStringFromStaticAscii("kana"); } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) { - return *isolate->factory()->NewStringFromAscii(CStrVector("ideo")); + return *isolate->factory()->NewStringFromStaticAscii("ideo"); } else { - return *isolate->factory()->NewStringFromAscii(CStrVector("unknown")); + return *isolate->factory()->NewStringFromStaticAscii("unknown"); } } #endif // V8_I18N_SUPPORT @@ -14249,8 +14497,6 @@ static Handle<Object> Runtime_GetScriptFromScriptName( Handle<Script> script; Factory* factory = script_name->GetIsolate()->factory(); Heap* heap = script_name->GetHeap(); - heap->EnsureHeapIsIterable(); - DisallowHeapAllocation no_allocation_during_heap_iteration; HeapIterator iterator(heap); HeapObject* obj = NULL; while (script.is_null() && ((obj = iterator.next()) != NULL)) { @@ -14268,14 +14514,14 @@ static Handle<Object> Runtime_GetScriptFromScriptName( if (script.is_null()) return factory->undefined_value(); // Return the script found. - return GetScriptWrapper(script); + return Script::GetWrapper(script); } // Get the script object from script data. NOTE: Regarding performance // see the NOTE for GetScriptFromScriptData. // args[0]: script data for the script to find the source for -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) { +RUNTIME_FUNCTION(Runtime_GetScript) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -14292,11 +14538,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) { // Collect the raw data for a stack trace. Returns an array of 4 // element segments each containing a receiver, function, code and // native code offset. -RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) { +RUNTIME_FUNCTION(Runtime_CollectStackTrace) { HandleScope scope(isolate); - ASSERT_EQ(args.length(), 3); + ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0); - Handle<Object> caller = args.at<Object>(1); + CONVERT_ARG_HANDLE_CHECKED(Object, caller, 1); CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]); // Optionally capture a more detailed stack trace for the message. @@ -14308,12 +14554,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) { // Retrieve the stack trace. This is the raw stack trace that yet has to // be formatted. Since we only need this once, clear it afterwards. -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAndClearOverflowedStackTrace) { +RUNTIME_FUNCTION(Runtime_GetAndClearOverflowedStackTrace) { HandleScope scope(isolate); - ASSERT_EQ(args.length(), 1); + ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0); Handle<String> key = isolate->factory()->hidden_stack_trace_string(); - Handle<Object> result(error_object->GetHiddenProperty(*key), isolate); + Handle<Object> result(error_object->GetHiddenProperty(key), isolate); if (result->IsTheHole()) return isolate->heap()->undefined_value(); RUNTIME_ASSERT(result->IsJSArray() || result->IsUndefined()); JSObject::DeleteHiddenProperty(error_object, key); @@ -14322,22 +14568,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAndClearOverflowedStackTrace) { // Returns V8 version as a string. -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) { - SealHandleScope shs(isolate); - ASSERT_EQ(args.length(), 0); +RUNTIME_FUNCTION(Runtime_GetV8Version) { + HandleScope scope(isolate); + ASSERT(args.length() == 0); const char* version_string = v8::V8::GetVersion(); - return isolate->heap()->AllocateStringFromOneByte(CStrVector(version_string), - NOT_TENURED); + return *isolate->factory()->NewStringFromAsciiChecked(version_string); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) { +RUNTIME_FUNCTION(Runtime_Abort) { SealHandleScope shs(isolate); - ASSERT(args.length() == 2); - OS::PrintError("abort: %s\n", - reinterpret_cast<char*>(args[0]) + args.smi_at(1)); + ASSERT(args.length() == 1); + CONVERT_SMI_ARG_CHECKED(message_id, 0); + const char* message = GetBailoutReason( + static_cast<BailoutReason>(message_id)); + OS::PrintError("abort: %s\n", message); isolate->PrintStack(stderr); OS::Abort(); UNREACHABLE(); @@ -14345,11 +14592,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_AbortJS) { +RUNTIME_FUNCTION(Runtime_AbortJS) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(String, message, 0); - OS::PrintError("abort: %s\n", *message->ToCString()); + OS::PrintError("abort: %s\n", message->ToCString().get()); isolate->PrintStack(stderr); OS::Abort(); UNREACHABLE(); @@ -14357,16 +14604,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_AbortJS) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_FlattenString) { +RUNTIME_FUNCTION(Runtime_FlattenString) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(String, str, 0); - FlattenString(str); - return isolate->heap()->undefined_value(); + return *String::Flatten(str); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyContextDisposed) { +RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) { HandleScope scope(isolate); ASSERT(args.length() == 0); isolate->heap()->NotifyContextDisposed(); @@ -14374,49 +14620,78 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyContextDisposed) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_MigrateInstance) { +RUNTIME_FUNCTION(Runtime_LoadMutableDouble) { + HandleScope scope(isolate); + ASSERT(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); + CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1); + RUNTIME_ASSERT((index->value() & 1) == 1); + FieldIndex field_index = + FieldIndex::ForLoadByFieldIndex(object->map(), index->value()); + if (field_index.is_inobject()) { + RUNTIME_ASSERT(field_index.property_index() < + object->map()->inobject_properties()); + } else { + RUNTIME_ASSERT(field_index.outobject_array_index() < + object->properties()->length()); + } + Handle<Object> raw_value(object->RawFastPropertyAt(field_index), isolate); + RUNTIME_ASSERT(raw_value->IsNumber() || raw_value->IsUninitialized()); + return *Object::NewStorageFor(isolate, raw_value, Representation::Double()); +} + + +RUNTIME_FUNCTION(Runtime_TryMigrateInstance) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); if (!object->IsJSObject()) return Smi::FromInt(0); Handle<JSObject> js_object = Handle<JSObject>::cast(object); if (!js_object->map()->is_deprecated()) return Smi::FromInt(0); - JSObject::MigrateInstance(js_object); + // This call must not cause lazy deopts, because it's called from deferred + // code where we can't handle lazy deopts for lack of a suitable bailout + // ID. So we just try migration and signal failure if necessary, + // which will also trigger a deopt. + if (!JSObject::TryMigrateInstance(js_object)) return Smi::FromInt(0); return *object; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) { +RUNTIME_FUNCTION(RuntimeHidden_GetFromCache) { SealHandleScope shs(isolate); // This is only called from codegen, so checks might be more lax. CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0); - Object* key = args[1]; + CONVERT_ARG_CHECKED(Object, key, 1); - int finger_index = cache->finger_index(); - Object* o = cache->get(finger_index); - if (o == key) { - // The fastest case: hit the same place again. - return cache->get(finger_index + 1); - } + { + DisallowHeapAllocation no_alloc; - for (int i = finger_index - 2; - i >= JSFunctionResultCache::kEntriesIndex; - i -= 2) { - o = cache->get(i); + int finger_index = cache->finger_index(); + Object* o = cache->get(finger_index); if (o == key) { - cache->set_finger_index(i); - return cache->get(i + 1); + // The fastest case: hit the same place again. + return cache->get(finger_index + 1); + } + + for (int i = finger_index - 2; + i >= JSFunctionResultCache::kEntriesIndex; + i -= 2) { + o = cache->get(i); + if (o == key) { + cache->set_finger_index(i); + return cache->get(i + 1); + } } - } - int size = cache->size(); - ASSERT(size <= cache->length()); + int size = cache->size(); + ASSERT(size <= cache->length()); - for (int i = size - 2; i > finger_index; i -= 2) { - o = cache->get(i); - if (o == key) { - cache->set_finger_index(i); - return cache->get(i + 1); + for (int i = size - 2; i > finger_index; i -= 2) { + o = cache->get(i); + if (o == key) { + cache->set_finger_index(i); + return cache->get(i + 1); + } } } @@ -14434,14 +14709,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) { isolate); // This handle is nor shared, nor used later, so it's safe. Handle<Object> argv[] = { key_handle }; - bool pending_exception; - value = Execution::Call(isolate, - factory, - receiver, - ARRAY_SIZE(argv), - argv, - &pending_exception); - if (pending_exception) return Failure::Exception(); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, value, + Execution::Call(isolate, factory, receiver, ARRAY_SIZE(argv), argv)); } #ifdef VERIFY_HEAP @@ -14451,8 +14721,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) { #endif // Function invocation may have cleared the cache. Reread all the data. - finger_index = cache_handle->finger_index(); - size = cache_handle->size(); + int finger_index = cache_handle->finger_index(); + int size = cache_handle->size(); // If we have spare room, put new data into it, otherwise evict post finger // entry which is likely to be the least recently used. @@ -14485,15 +14755,17 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) { +RUNTIME_FUNCTION(Runtime_MessageGetStartPosition) { SealHandleScope shs(isolate); + ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSMessageObject, message, 0); return Smi::FromInt(message->start_position()); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) { +RUNTIME_FUNCTION(Runtime_MessageGetScript) { SealHandleScope shs(isolate); + ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSMessageObject, message, 0); return message->script(); } @@ -14502,14 +14774,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) { #ifdef DEBUG // ListNatives is ONLY used by the fuzz-natives.js in debug mode // Exclude the code in release mode. -RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) { +RUNTIME_FUNCTION(Runtime_ListNatives) { HandleScope scope(isolate); ASSERT(args.length() == 0); #define COUNT_ENTRY(Name, argc, ressize) + 1 int entry_count = 0 RUNTIME_FUNCTION_LIST(COUNT_ENTRY) + RUNTIME_HIDDEN_FUNCTION_LIST(COUNT_ENTRY) INLINE_FUNCTION_LIST(COUNT_ENTRY) - INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY); + INLINE_OPTIMIZED_FUNCTION_LIST(COUNT_ENTRY); #undef COUNT_ENTRY Factory* factory = isolate->factory(); Handle<FixedArray> elements = factory->NewFixedArray(entry_count); @@ -14521,11 +14794,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) { Handle<String> name; \ /* Inline runtime functions have an underscore in front of the name. */ \ if (inline_runtime_functions) { \ - name = factory->NewStringFromAscii( \ - Vector<const char>("_" #Name, StrLength("_" #Name))); \ + name = factory->NewStringFromStaticAscii("_" #Name); \ } else { \ - name = factory->NewStringFromAscii( \ - Vector<const char>(#Name, StrLength(#Name))); \ + name = factory->NewStringFromStaticAscii(#Name); \ } \ Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \ pair_elements->set(0, *name); \ @@ -14535,9 +14806,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) { } inline_runtime_functions = false; RUNTIME_FUNCTION_LIST(ADD_ENTRY) + INLINE_OPTIMIZED_FUNCTION_LIST(ADD_ENTRY) + // Calling hidden runtime functions should just throw. + RUNTIME_HIDDEN_FUNCTION_LIST(ADD_ENTRY) inline_runtime_functions = true; INLINE_FUNCTION_LIST(ADD_ENTRY) - INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY) #undef ADD_ENTRY ASSERT_EQ(index, entry_count); Handle<JSArray> result = factory->NewJSArrayWithElements(elements); @@ -14546,29 +14819,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) { #endif -RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) { - SealHandleScope shs(isolate); - ASSERT(args.length() == 2); - CONVERT_ARG_CHECKED(String, format, 0); - CONVERT_ARG_CHECKED(JSArray, elms, 1); - DisallowHeapAllocation no_gc; - String::FlatContent format_content = format->GetFlatContent(); - RUNTIME_ASSERT(format_content.IsAscii()); - Vector<const uint8_t> chars = format_content.ToOneByteVector(); - isolate->logger()->LogRuntime(Vector<const char>::cast(chars), elms); - return isolate->heap()->undefined_value(); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) { +RUNTIME_FUNCTION(Runtime_IS_VAR) { UNREACHABLE(); // implemented as macro in the parser return NULL; } #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \ - RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \ - CONVERT_ARG_CHECKED(JSObject, obj, 0); \ + RUNTIME_FUNCTION(Runtime_Has##Name) { \ + CONVERT_ARG_CHECKED(JSObject, obj, 0); \ return isolate->heap()->ToBoolean(obj->Has##Name()); \ } @@ -14578,24 +14837,37 @@ ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements) ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements) ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements) ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements) -ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(NonStrictArgumentsElements) -ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements) +ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements) ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements) -ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements) -ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements) -ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements) -ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements) -ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements) -ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements) -ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements) -ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements) // Properties test sitting with elements tests - not fooling anyone. ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties) #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION -RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) { +#define TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, size) \ + RUNTIME_FUNCTION(Runtime_HasExternal##Type##Elements) { \ + CONVERT_ARG_CHECKED(JSObject, obj, 0); \ + return isolate->heap()->ToBoolean(obj->HasExternal##Type##Elements()); \ + } + +TYPED_ARRAYS(TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION) + +#undef TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION + + +#define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \ + RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) { \ + CONVERT_ARG_CHECKED(JSObject, obj, 0); \ + return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements()); \ + } + +TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION) + +#undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION + + +RUNTIME_FUNCTION(Runtime_HaveSameMap) { SealHandleScope shs(isolate); ASSERT(args.length() == 2); CONVERT_ARG_CHECKED(JSObject, obj1, 0); @@ -14604,69 +14876,64 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAccessCheckNeeded) { +RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); - CONVERT_ARG_CHECKED(HeapObject, obj, 0); - return isolate->heap()->ToBoolean(obj->IsAccessCheckNeeded()); + CONVERT_ARG_CHECKED(Object, obj, 0); + return isolate->heap()->ToBoolean(obj->IsJSGlobalProxy()); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsObserved) { +RUNTIME_FUNCTION(Runtime_IsObserved) { SealHandleScope shs(isolate); ASSERT(args.length() == 1); if (!args[0]->IsJSReceiver()) return isolate->heap()->false_value(); - JSReceiver* obj = JSReceiver::cast(args[0]); - if (obj->IsJSGlobalProxy()) { - Object* proto = obj->GetPrototype(); - if (proto->IsNull()) return isolate->heap()->false_value(); - ASSERT(proto->IsJSGlobalObject()); - obj = JSReceiver::cast(proto); - } + CONVERT_ARG_CHECKED(JSReceiver, obj, 0); + ASSERT(!obj->IsJSGlobalProxy() || !obj->map()->is_observed()); return isolate->heap()->ToBoolean(obj->map()->is_observed()); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetIsObserved) { +RUNTIME_FUNCTION(Runtime_SetIsObserved) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0); - if (obj->IsJSGlobalProxy()) { - Object* proto = obj->GetPrototype(); - if (proto->IsNull()) return isolate->heap()->undefined_value(); - ASSERT(proto->IsJSGlobalObject()); - obj = handle(JSReceiver::cast(proto)); - } - if (obj->IsJSProxy()) - return isolate->heap()->undefined_value(); + RUNTIME_ASSERT(!obj->IsJSGlobalProxy()); + if (obj->IsJSProxy()) return isolate->heap()->undefined_value(); + RUNTIME_ASSERT(!obj->map()->is_observed()); - ASSERT(!(obj->map()->is_observed() && obj->IsJSObject() && - Handle<JSObject>::cast(obj)->HasFastElements())); ASSERT(obj->IsJSObject()); JSObject::SetObserved(Handle<JSObject>::cast(obj)); return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_SetMicrotaskPending) { - SealHandleScope shs(isolate); +RUNTIME_FUNCTION(Runtime_EnqueueMicrotask) { + HandleScope scope(isolate); ASSERT(args.length() == 1); - CONVERT_BOOLEAN_ARG_CHECKED(new_state, 0); - bool old_state = isolate->microtask_pending(); - isolate->set_microtask_pending(new_state); - return isolate->heap()->ToBoolean(old_state); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, microtask, 0); + isolate->EnqueueMicrotask(microtask); + return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetObservationState) { +RUNTIME_FUNCTION(Runtime_RunMicrotasks) { + HandleScope scope(isolate); + ASSERT(args.length() == 0); + isolate->RunMicrotasks(); + return isolate->heap()->undefined_value(); +} + + +RUNTIME_FUNCTION(Runtime_GetObservationState) { SealHandleScope shs(isolate); ASSERT(args.length() == 0); return isolate->heap()->observation_state(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ObservationWeakMapCreate) { +RUNTIME_FUNCTION(Runtime_ObservationWeakMapCreate) { HandleScope scope(isolate); ASSERT(args.length() == 0); // TODO(adamk): Currently this runtime function is only called three times per @@ -14676,60 +14943,87 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ObservationWeakMapCreate) { isolate->factory()->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize); Handle<JSWeakMap> weakmap = Handle<JSWeakMap>::cast(isolate->factory()->NewJSObjectFromMap(map)); - return WeakCollectionInitialize(isolate, weakmap); + return *WeakCollectionInitialize(isolate, weakmap); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_UnwrapGlobalProxy) { - SealHandleScope shs(isolate); - ASSERT(args.length() == 1); - Object* object = args[0]; - if (object->IsJSGlobalProxy()) { - object = object->GetPrototype(isolate); - if (object->IsNull()) return isolate->heap()->undefined_value(); - } - return object; +static bool ContextsHaveSameOrigin(Handle<Context> context1, + Handle<Context> context2) { + return context1->security_token() == context2->security_token(); } -RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAccessAllowedForObserver) { +RUNTIME_FUNCTION(Runtime_ObserverObjectAndRecordHaveSameOrigin) { HandleScope scope(isolate); ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSFunction, observer, 0); CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 1); - ASSERT(object->IsAccessCheckNeeded()); - Handle<Object> key = args.at<Object>(2); - SaveContext save(isolate); - isolate->set_context(observer->context()); - if (!isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(), - v8::ACCESS_KEYS)) { - return isolate->heap()->false_value(); - } - bool access_allowed = false; - uint32_t index = 0; - if (key->ToArrayIndex(&index) || - (key->IsString() && String::cast(*key)->AsArrayIndex(&index))) { - access_allowed = - isolate->MayIndexedAccess(*object, index, v8::ACCESS_GET) && - isolate->MayIndexedAccess(*object, index, v8::ACCESS_HAS); - } else { - access_allowed = isolate->MayNamedAccess(*object, *key, v8::ACCESS_GET) && - isolate->MayNamedAccess(*object, *key, v8::ACCESS_HAS); - } - return isolate->heap()->ToBoolean(access_allowed); + CONVERT_ARG_HANDLE_CHECKED(JSObject, record, 2); + + Handle<Context> observer_context(observer->context()->native_context(), + isolate); + Handle<Context> object_context(object->GetCreationContext()); + Handle<Context> record_context(record->GetCreationContext()); + + return isolate->heap()->ToBoolean( + ContextsHaveSameOrigin(object_context, observer_context) && + ContextsHaveSameOrigin(object_context, record_context)); +} + + +RUNTIME_FUNCTION(Runtime_ObjectWasCreatedInCurrentOrigin) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); + + Handle<Context> creation_context(object->GetCreationContext(), isolate); + return isolate->heap()->ToBoolean( + ContextsHaveSameOrigin(creation_context, isolate->native_context())); } -static MaybeObject* ArrayConstructorCommon(Isolate* isolate, +RUNTIME_FUNCTION(Runtime_GetObjectContextObjectObserve) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); + + Handle<Context> context(object->GetCreationContext(), isolate); + return context->native_object_observe(); +} + + +RUNTIME_FUNCTION(Runtime_GetObjectContextObjectGetNotifier) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); + + Handle<Context> context(object->GetCreationContext(), isolate); + return context->native_object_get_notifier(); +} + + +RUNTIME_FUNCTION(Runtime_GetObjectContextNotifierPerformChange) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(JSObject, object_info, 0); + + Handle<Context> context(object_info->GetCreationContext(), isolate); + return context->native_object_notifier_perform_change(); +} + + +static Object* ArrayConstructorCommon(Isolate* isolate, Handle<JSFunction> constructor, Handle<AllocationSite> site, Arguments* caller_args) { + Factory* factory = isolate->factory(); + bool holey = false; bool can_use_type_feedback = true; if (caller_args->length() == 1) { - Object* argument_one = (*caller_args)[0]; + Handle<Object> argument_one = caller_args->at<Object>(0); if (argument_one->IsSmi()) { - int value = Smi::cast(argument_one)->value(); + int value = Handle<Smi>::cast(argument_one)->value(); if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) { // the array is a dictionary in this case. can_use_type_feedback = false; @@ -14742,8 +15036,7 @@ static MaybeObject* ArrayConstructorCommon(Isolate* isolate, } } - JSArray* array; - MaybeObject* maybe_array; + Handle<JSArray> array; if (!site.is_null() && can_use_type_feedback) { ElementsKind to_kind = site->GetElementsKind(); if (holey && !IsFastHoleyElementsKind(to_kind)) { @@ -14752,27 +15045,39 @@ static MaybeObject* ArrayConstructorCommon(Isolate* isolate, site->SetElementsKind(to_kind); } - maybe_array = isolate->heap()->AllocateJSObjectWithAllocationSite( - *constructor, site); - if (!maybe_array->To(&array)) return maybe_array; + // We should allocate with an initial map that reflects the allocation site + // advice. Therefore we use AllocateJSObjectFromMap instead of passing + // the constructor. + Handle<Map> initial_map(constructor->initial_map(), isolate); + if (to_kind != initial_map->elements_kind()) { + initial_map = Map::AsElementsKind(initial_map, to_kind); + } + + // If we don't care to track arrays of to_kind ElementsKind, then + // don't emit a memento for them. + Handle<AllocationSite> allocation_site; + if (AllocationSite::GetMode(to_kind) == TRACK_ALLOCATION_SITE) { + allocation_site = site; + } + + array = Handle<JSArray>::cast(factory->NewJSObjectFromMap( + initial_map, NOT_TENURED, true, allocation_site)); } else { - maybe_array = isolate->heap()->AllocateJSObject(*constructor); - if (!maybe_array->To(&array)) return maybe_array; + array = Handle<JSArray>::cast(factory->NewJSObject(constructor)); + // We might need to transition to holey ElementsKind kind = constructor->initial_map()->elements_kind(); if (holey && !IsFastHoleyElementsKind(kind)) { kind = GetHoleyElementsKind(kind); - maybe_array = array->TransitionElementsKind(kind); - if (maybe_array->IsFailure()) return maybe_array; + JSObject::TransitionElementsKind(array, kind); } } - maybe_array = isolate->heap()->AllocateJSArrayStorage(array, 0, 0, - DONT_INITIALIZE_ARRAY_ELEMENTS); - if (maybe_array->IsFailure()) return maybe_array; + factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS); + ElementsKind old_kind = array->GetElementsKind(); - maybe_array = ArrayConstructInitializeElements(array, caller_args); - if (maybe_array->IsFailure()) return maybe_array; + RETURN_FAILURE_ON_EXCEPTION( + isolate, ArrayConstructInitializeElements(array, caller_args)); if (!site.is_null() && (old_kind != array->GetElementsKind() || !can_use_type_feedback)) { @@ -14781,11 +15086,11 @@ static MaybeObject* ArrayConstructorCommon(Isolate* isolate, // We must mark the allocationsite as un-inlinable. site->SetDoNotInlineCall(); } - return array; + return *array; } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) { +RUNTIME_FUNCTION(RuntimeHidden_ArrayConstructor) { HandleScope scope(isolate); // If we get 2 arguments then they are the stub parameters (constructor, type // info). If we get 4, then the first one is a pointer to the arguments @@ -14810,10 +15115,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) { Handle<AllocationSite> site; if (!type_info.is_null() && - *type_info != isolate->heap()->undefined_value() && - Cell::cast(*type_info)->value()->IsAllocationSite()) { - site = Handle<AllocationSite>( - AllocationSite::cast(Cell::cast(*type_info)->value()), isolate); + *type_info != isolate->heap()->undefined_value()) { + site = Handle<AllocationSite>::cast(type_info); ASSERT(!site->SitePointsToLiteral()); } @@ -14824,7 +15127,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalArrayConstructor) { +RUNTIME_FUNCTION(RuntimeHidden_InternalArrayConstructor) { HandleScope scope(isolate); Arguments empty_args(0, NULL); bool no_caller_args = args.length() == 1; @@ -14847,7 +15150,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalArrayConstructor) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_MaxSmi) { +RUNTIME_FUNCTION(Runtime_MaxSmi) { + ASSERT(args.length() == 0); return Smi::FromInt(Smi::kMaxValue); } @@ -14860,46 +15164,56 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_MaxSmi) { FUNCTION_ADDR(Runtime_##name), number_of_args, result_size }, +#define FH(name, number_of_args, result_size) \ + { Runtime::kHidden##name, Runtime::RUNTIME_HIDDEN, NULL, \ + FUNCTION_ADDR(RuntimeHidden_##name), number_of_args, result_size }, + + #define I(name, number_of_args, result_size) \ { Runtime::kInline##name, Runtime::INLINE, \ "_" #name, NULL, number_of_args, result_size }, + +#define IO(name, number_of_args, result_size) \ + { Runtime::kInlineOptimized##name, Runtime::INLINE_OPTIMIZED, \ + "_" #name, FUNCTION_ADDR(Runtime_##name), number_of_args, result_size }, + + static const Runtime::Function kIntrinsicFunctions[] = { RUNTIME_FUNCTION_LIST(F) + INLINE_OPTIMIZED_FUNCTION_LIST(F) + RUNTIME_HIDDEN_FUNCTION_LIST(FH) INLINE_FUNCTION_LIST(I) - INLINE_RUNTIME_FUNCTION_LIST(I) + INLINE_OPTIMIZED_FUNCTION_LIST(IO) }; +#undef IO +#undef I +#undef FH +#undef F + -MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap, - Object* dictionary) { - ASSERT(dictionary != NULL); - ASSERT(NameDictionary::cast(dictionary)->NumberOfElements() == 0); +void Runtime::InitializeIntrinsicFunctionNames(Isolate* isolate, + Handle<NameDictionary> dict) { + ASSERT(dict->NumberOfElements() == 0); + HandleScope scope(isolate); for (int i = 0; i < kNumFunctions; ++i) { - Object* name_string; - { MaybeObject* maybe_name_string = - heap->InternalizeUtf8String(kIntrinsicFunctions[i].name); - if (!maybe_name_string->ToObject(&name_string)) return maybe_name_string; - } - NameDictionary* name_dictionary = NameDictionary::cast(dictionary); - { MaybeObject* maybe_dictionary = name_dictionary->Add( - String::cast(name_string), - Smi::FromInt(i), - PropertyDetails(NONE, NORMAL, Representation::None())); - if (!maybe_dictionary->ToObject(&dictionary)) { - // Non-recoverable failure. Calling code must restart heap - // initialization. - return maybe_dictionary; - } - } + const char* name = kIntrinsicFunctions[i].name; + if (name == NULL) continue; + Handle<NameDictionary> new_dict = NameDictionary::Add( + dict, + isolate->factory()->InternalizeUtf8String(name), + Handle<Smi>(Smi::FromInt(i), isolate), + PropertyDetails(NONE, NORMAL, Representation::None())); + // The dictionary does not need to grow. + CHECK(new_dict.is_identical_to(dict)); } - return dictionary; } const Runtime::Function* Runtime::FunctionForName(Handle<String> name) { Heap* heap = name->GetHeap(); - int entry = heap->intrinsic_function_names()->FindEntry(*name); + int entry = heap->intrinsic_function_names()->FindEntry(name); if (entry != kNotFound) { Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry); int function_index = Smi::cast(smi_index)->value(); @@ -14913,26 +15227,4 @@ const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) { return &(kIntrinsicFunctions[static_cast<int>(id)]); } - -void Runtime::PerformGC(Object* result, Isolate* isolate) { - Failure* failure = Failure::cast(result); - if (failure->IsRetryAfterGC()) { - if (isolate->heap()->new_space()->AddFreshPage()) { - return; - } - - // Try to do a garbage collection; ignore it if it fails. The C - // entry stub will throw an out-of-memory exception in that case. - isolate->heap()->CollectGarbage(failure->allocation_space(), - "Runtime::PerformGC"); - } else { - // Handle last resort GC and make sure to allow future allocations - // to grow the heap without causing GCs (if possible). - isolate->counters()->gc_last_resort_from_js()->Increment(); - isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, - "Runtime::PerformGC"); - } -} - - } } // namespace v8::internal |