blob: 48ff69f5d273071e0615743e2b2760f2abb71e70 [file] [log] [blame]
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001// Copyright 2010 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
43#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000044#include "liveedit.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000045#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "platform.h"
47#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000048#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000050#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000051#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000052#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000053#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
kasperl@chromium.org71affb52009-05-26 05:44:31 +000055namespace v8 {
56namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
58
ager@chromium.org3e875802009-06-29 08:26:34 +000059#define RUNTIME_ASSERT(value) \
60 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
62// Cast the given object to a value of the specified type and store
63// it in a variable with the given name. If the object is not of the
64// expected type call IllegalOperation and return.
65#define CONVERT_CHECKED(Type, name, obj) \
66 RUNTIME_ASSERT(obj->Is##Type()); \
67 Type* name = Type::cast(obj);
68
69#define CONVERT_ARG_CHECKED(Type, name, index) \
70 RUNTIME_ASSERT(args[index]->Is##Type()); \
71 Handle<Type> name = args.at<Type>(index);
72
kasper.lundbd3ec4e2008-07-09 11:06:54 +000073// Cast the given object to a boolean and store it in a variable with
74// the given name. If the object is not a boolean call IllegalOperation
75// and return.
76#define CONVERT_BOOLEAN_CHECKED(name, obj) \
77 RUNTIME_ASSERT(obj->IsBoolean()); \
78 bool name = (obj)->IsTrue();
79
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000080// Cast the given object to a Smi and store its value in an int variable
81// with the given name. If the object is not a Smi call IllegalOperation
82// and return.
83#define CONVERT_SMI_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsSmi()); \
85 int name = Smi::cast(obj)->value();
86
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087// Cast the given object to a double and store it in a variable with
88// the given name. If the object is not a number (as opposed to
89// the number not-a-number) call IllegalOperation and return.
90#define CONVERT_DOUBLE_CHECKED(name, obj) \
91 RUNTIME_ASSERT(obj->IsNumber()); \
92 double name = (obj)->Number();
93
94// Call the specified converter on the object *comand store the result in
95// a variable of the specified type with the given name. If the
96// object is not a Number call IllegalOperation and return.
97#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
98 RUNTIME_ASSERT(obj->IsNumber()); \
99 type name = NumberTo##Type(obj);
100
101// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000102static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
104
lrn@chromium.org303ada72010-10-27 09:33:13 +0000105MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000106 StackLimitCheck check;
107 if (check.HasOverflowed()) return Top::StackOverflow();
108
lrn@chromium.org303ada72010-10-27 09:33:13 +0000109 Object* result;
110 { MaybeObject* maybe_result = Heap::CopyJSObject(boilerplate);
111 if (!maybe_result->ToObject(&result)) return maybe_result;
112 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000113 JSObject* copy = JSObject::cast(result);
114
115 // Deep copy local properties.
116 if (copy->HasFastProperties()) {
117 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 for (int i = 0; i < properties->length(); i++) {
119 Object* value = properties->get(i);
120 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000121 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000122 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
123 if (!maybe_result->ToObject(&result)) return maybe_result;
124 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000126 }
127 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000128 int nof = copy->map()->inobject_properties();
129 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 Object* value = copy->InObjectPropertyAt(i);
131 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000132 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000133 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
134 if (!maybe_result->ToObject(&result)) return maybe_result;
135 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000136 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000137 }
138 }
139 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000140 { MaybeObject* maybe_result =
141 Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
142 if (!maybe_result->ToObject(&result)) return maybe_result;
143 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000144 FixedArray* names = FixedArray::cast(result);
145 copy->GetLocalPropertyNames(names, 0);
146 for (int i = 0; i < names->length(); i++) {
147 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000150 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 // Only deep copy fields from the object literal expression.
152 // In particular, don't try to copy the length attribute of
153 // an array.
154 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000155 Object* value =
156 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000158 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
160 if (!maybe_result->ToObject(&result)) return maybe_result;
161 }
162 { MaybeObject* maybe_result =
163 copy->SetProperty(key_string, result, NONE);
164 if (!maybe_result->ToObject(&result)) return maybe_result;
165 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000166 }
167 }
168 }
169
170 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000171 // Pixel elements cannot be created using an object literal.
ager@chromium.org3811b432009-10-28 14:53:37 +0000172 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000173 switch (copy->GetElementsKind()) {
174 case JSObject::FAST_ELEMENTS: {
175 FixedArray* elements = FixedArray::cast(copy->elements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000176 if (elements->map() == Heap::fixed_cow_array_map()) {
177 Counters::cow_arrays_created_runtime.Increment();
178#ifdef DEBUG
179 for (int i = 0; i < elements->length(); i++) {
180 ASSERT(!elements->get(i)->IsJSObject());
181 }
182#endif
183 } else {
184 for (int i = 0; i < elements->length(); i++) {
185 Object* value = elements->get(i);
186 if (value->IsJSObject()) {
187 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000188 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
189 if (!maybe_result->ToObject(&result)) return maybe_result;
190 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000191 elements->set(i, result);
192 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 }
194 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000195 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000197 case JSObject::DICTIONARY_ELEMENTS: {
198 NumberDictionary* element_dictionary = copy->element_dictionary();
199 int capacity = element_dictionary->Capacity();
200 for (int i = 0; i < capacity; i++) {
201 Object* k = element_dictionary->KeyAt(i);
202 if (element_dictionary->IsKey(k)) {
203 Object* value = element_dictionary->ValueAt(i);
204 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000205 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000206 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
207 if (!maybe_result->ToObject(&result)) return maybe_result;
208 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000209 element_dictionary->ValueAtPut(i, result);
210 }
211 }
212 }
213 break;
214 }
215 default:
216 UNREACHABLE();
217 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000218 }
219 return copy;
220}
221
222
lrn@chromium.org303ada72010-10-27 09:33:13 +0000223static MaybeObject* Runtime_CloneLiteralBoilerplate(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000224 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
225 return DeepCopyBoilerplate(boilerplate);
226}
227
228
lrn@chromium.org303ada72010-10-27 09:33:13 +0000229static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000231 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000232}
233
234
ager@chromium.org236ad962008-09-25 09:45:57 +0000235static Handle<Map> ComputeObjectLiteralMap(
236 Handle<Context> context,
237 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000238 bool* is_result_from_cache) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000239 int properties_length = constant_properties->length();
240 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000241 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000242 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000243 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000244 for (int p = 0; p != properties_length; p += 2) {
245 Object* key = constant_properties->get(p);
246 uint32_t element_index = 0;
247 if (key->IsSymbol()) {
248 number_of_symbol_keys++;
249 } else if (key->ToArrayIndex(&element_index)) {
250 // An index key does not require space in the property backing store.
251 number_of_properties--;
252 } else {
253 // Bail out as a non-symbol non-index key makes caching impossible.
254 // ASSERT to make sure that the if condition after the loop is false.
255 ASSERT(number_of_symbol_keys != number_of_properties);
256 break;
257 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000258 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000259 // If we only have symbols and array indices among keys then we can
260 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000262 if ((number_of_symbol_keys == number_of_properties) &&
263 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 // Create the fixed array with the key.
265 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000266 if (number_of_symbol_keys > 0) {
267 int index = 0;
268 for (int p = 0; p < properties_length; p += 2) {
269 Object* key = constant_properties->get(p);
270 if (key->IsSymbol()) {
271 keys->set(index++, key);
272 }
273 }
274 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000275 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000276 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000277 return Factory::ObjectLiteralMapFromCache(context, keys);
278 }
279 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000280 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000281 return Factory::CopyMap(
282 Handle<Map>(context->object_function()->initial_map()),
283 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284}
285
286
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000287static Handle<Object> CreateLiteralBoilerplate(
288 Handle<FixedArray> literals,
289 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000290
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000291
292static Handle<Object> CreateObjectLiteralBoilerplate(
293 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000294 Handle<FixedArray> constant_properties,
295 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000296 // Get the global context from the literals array. This is the
297 // context in which the function was created and we use the object
298 // function from this context to create the object literal. We do
299 // not use the object function from the current global context
300 // because this might be the object function from another context
301 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000302 Handle<Context> context =
303 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
304
305 bool is_result_from_cache;
306 Handle<Map> map = ComputeObjectLiteralMap(context,
307 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000308 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309
ager@chromium.org236ad962008-09-25 09:45:57 +0000310 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000311
312 // Normalize the elements of the boilerplate to save space if needed.
313 if (!should_have_fast_elements) NormalizeElements(boilerplate);
314
ager@chromium.org32912102009-01-16 10:38:43 +0000315 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000316 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000317 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000318 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000319 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 for (int index = 0; index < length; index +=2) {
321 Handle<Object> key(constant_properties->get(index+0));
322 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323 if (value->IsFixedArray()) {
324 // The value contains the constant_properties of a
325 // simple object literal.
326 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
327 value = CreateLiteralBoilerplate(literals, array);
328 if (value.is_null()) return value;
329 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000330 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000331 uint32_t element_index = 0;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000332 if (key->IsSymbol()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000333 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
334 // Array index as string (uint32).
335 result = SetOwnElement(boilerplate, element_index, value);
336 } else {
337 Handle<String> name(String::cast(*key));
338 ASSERT(!name->AsArrayIndex(&element_index));
339 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
340 value, NONE);
341 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000342 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 // Array index (uint32).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000344 result = SetOwnElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345 } else {
346 // Non-uint32 number.
347 ASSERT(key->IsNumber());
348 double num = key->Number();
349 char arr[100];
350 Vector<char> buffer(arr, ARRAY_SIZE(arr));
351 const char* str = DoubleToCString(num, buffer);
352 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000353 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
354 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000356 // If setting the property on the boilerplate throws an
357 // exception, the exception is converted to an empty handle in
358 // the handle based operations. In that case, we need to
359 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000360 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 }
362 }
363
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000364 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000365}
366
367
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000368static Handle<Object> CreateArrayLiteralBoilerplate(
369 Handle<FixedArray> literals,
370 Handle<FixedArray> elements) {
371 // Create the JSArray.
372 Handle<JSFunction> constructor(
373 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
374 Handle<Object> object = Factory::NewJSObject(constructor);
375
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000376 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
377 Handle<FixedArray> copied_elements =
378 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000379
380 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000381 if (is_cow) {
382#ifdef DEBUG
383 // Copy-on-write arrays must be shallow (and simple).
384 for (int i = 0; i < content->length(); i++) {
385 ASSERT(!content->get(i)->IsFixedArray());
386 }
387#endif
388 } else {
389 for (int i = 0; i < content->length(); i++) {
390 if (content->get(i)->IsFixedArray()) {
391 // The value contains the constant_properties of a
392 // simple object literal.
393 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
394 Handle<Object> result =
395 CreateLiteralBoilerplate(literals, fa);
396 if (result.is_null()) return result;
397 content->set(i, *result);
398 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000399 }
400 }
401
402 // Set the elements.
403 Handle<JSArray>::cast(object)->SetContent(*content);
404 return object;
405}
406
407
408static Handle<Object> CreateLiteralBoilerplate(
409 Handle<FixedArray> literals,
410 Handle<FixedArray> array) {
411 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
412 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000413 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
414 return CreateObjectLiteralBoilerplate(literals, elements, true);
415 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
416 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000417 case CompileTimeValue::ARRAY_LITERAL:
418 return CreateArrayLiteralBoilerplate(literals, elements);
419 default:
420 UNREACHABLE();
421 return Handle<Object>::null();
422 }
423}
424
425
lrn@chromium.org303ada72010-10-27 09:33:13 +0000426static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000427 // Takes a FixedArray of elements containing the literal elements of
428 // the array literal and produces JSArray with those elements.
429 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000430 // which contains the context from which to get the Array function
431 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432 HandleScope scope;
433 ASSERT(args.length() == 3);
434 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
435 CONVERT_SMI_CHECKED(literals_index, args[1]);
436 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
439 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000441 // Update the functions literal and return the boilerplate.
442 literals->set(literals_index, *object);
443 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444}
445
446
lrn@chromium.org303ada72010-10-27 09:33:13 +0000447static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000448 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000449 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000450 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
451 CONVERT_SMI_CHECKED(literals_index, args[1]);
452 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000453 CONVERT_SMI_CHECKED(fast_elements, args[3]);
454 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000455
456 // Check if boilerplate exists. If not, create it first.
457 Handle<Object> boilerplate(literals->get(literals_index));
458 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000459 boilerplate = CreateObjectLiteralBoilerplate(literals,
460 constant_properties,
461 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000462 if (boilerplate.is_null()) return Failure::Exception();
463 // Update the functions literal and return the boilerplate.
464 literals->set(literals_index, *boilerplate);
465 }
466 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
467}
468
469
lrn@chromium.org303ada72010-10-27 09:33:13 +0000470static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000471 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000472 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000473 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
474 CONVERT_SMI_CHECKED(literals_index, args[1]);
475 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000476 CONVERT_SMI_CHECKED(fast_elements, args[3]);
477 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000478
479 // Check if boilerplate exists. If not, create it first.
480 Handle<Object> boilerplate(literals->get(literals_index));
481 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000482 boilerplate = CreateObjectLiteralBoilerplate(literals,
483 constant_properties,
484 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000485 if (boilerplate.is_null()) return Failure::Exception();
486 // Update the functions literal and return the boilerplate.
487 literals->set(literals_index, *boilerplate);
488 }
489 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
490}
491
492
lrn@chromium.org303ada72010-10-27 09:33:13 +0000493static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000494 HandleScope scope;
495 ASSERT(args.length() == 3);
496 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
497 CONVERT_SMI_CHECKED(literals_index, args[1]);
498 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
499
500 // Check if boilerplate exists. If not, create it first.
501 Handle<Object> boilerplate(literals->get(literals_index));
502 if (*boilerplate == Heap::undefined_value()) {
503 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
504 if (boilerplate.is_null()) return Failure::Exception();
505 // Update the functions literal and return the boilerplate.
506 literals->set(literals_index, *boilerplate);
507 }
508 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
509}
510
511
lrn@chromium.org303ada72010-10-27 09:33:13 +0000512static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000513 HandleScope scope;
514 ASSERT(args.length() == 3);
515 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
516 CONVERT_SMI_CHECKED(literals_index, args[1]);
517 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
518
519 // Check if boilerplate exists. If not, create it first.
520 Handle<Object> boilerplate(literals->get(literals_index));
521 if (*boilerplate == Heap::undefined_value()) {
522 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
523 if (boilerplate.is_null()) return Failure::Exception();
524 // Update the functions literal and return the boilerplate.
525 literals->set(literals_index, *boilerplate);
526 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000527 if (JSObject::cast(*boilerplate)->elements()->map() ==
528 Heap::fixed_cow_array_map()) {
529 Counters::cow_arrays_created_runtime.Increment();
530 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000531 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
532}
533
534
lrn@chromium.org303ada72010-10-27 09:33:13 +0000535static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
ager@chromium.org32912102009-01-16 10:38:43 +0000536 ASSERT(args.length() == 2);
537 CONVERT_CHECKED(String, key, args[0]);
538 Object* value = args[1];
539 // Create a catch context extension object.
540 JSFunction* constructor =
541 Top::context()->global_context()->context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000542 Object* object;
543 { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
544 if (!maybe_object->ToObject(&object)) return maybe_object;
545 }
ager@chromium.org32912102009-01-16 10:38:43 +0000546 // Assign the exception value to the catch variable and make sure
547 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000548 { MaybeObject* maybe_value =
549 JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
550 if (!maybe_value->ToObject(&value)) return maybe_value;
551 }
ager@chromium.org32912102009-01-16 10:38:43 +0000552 return object;
553}
554
555
lrn@chromium.org303ada72010-10-27 09:33:13 +0000556static MaybeObject* Runtime_ClassOf(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 NoHandleAllocation ha;
558 ASSERT(args.length() == 1);
559 Object* obj = args[0];
560 if (!obj->IsJSObject()) return Heap::null_value();
561 return JSObject::cast(obj)->class_name();
562}
563
ager@chromium.org7c537e22008-10-16 08:43:32 +0000564
lrn@chromium.org303ada72010-10-27 09:33:13 +0000565static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 NoHandleAllocation ha;
567 ASSERT(args.length() == 2);
568 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
569 Object* O = args[0];
570 Object* V = args[1];
571 while (true) {
572 Object* prototype = V->GetPrototype();
573 if (prototype->IsNull()) return Heap::false_value();
574 if (O == prototype) return Heap::true_value();
575 V = prototype;
576 }
577}
578
579
ager@chromium.org9085a012009-05-11 19:22:57 +0000580// Inserts an object as the hidden prototype of another object.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000581static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000582 NoHandleAllocation ha;
583 ASSERT(args.length() == 2);
584 CONVERT_CHECKED(JSObject, jsobject, args[0]);
585 CONVERT_CHECKED(JSObject, proto, args[1]);
586
587 // Sanity checks. The old prototype (that we are replacing) could
588 // theoretically be null, but if it is not null then check that we
589 // didn't already install a hidden prototype here.
590 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
591 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
592 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
593
594 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000595 Object* map_or_failure;
596 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
597 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
598 return maybe_map_or_failure;
599 }
600 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000601 Map* new_proto_map = Map::cast(map_or_failure);
602
lrn@chromium.org303ada72010-10-27 09:33:13 +0000603 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
604 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
605 return maybe_map_or_failure;
606 }
607 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000608 Map* new_map = Map::cast(map_or_failure);
609
610 // Set proto's prototype to be the old prototype of the object.
611 new_proto_map->set_prototype(jsobject->GetPrototype());
612 proto->set_map(new_proto_map);
613 new_proto_map->set_is_hidden_prototype();
614
615 // Set the object's prototype to proto.
616 new_map->set_prototype(proto);
617 jsobject->set_map(new_map);
618
619 return Heap::undefined_value();
620}
621
622
lrn@chromium.org303ada72010-10-27 09:33:13 +0000623static MaybeObject* Runtime_IsConstructCall(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000625 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626 JavaScriptFrameIterator it;
627 return Heap::ToBoolean(it.frame()->IsConstructor());
628}
629
630
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000631// Recursively traverses hidden prototypes if property is not found
632static void GetOwnPropertyImplementation(JSObject* obj,
633 String* name,
634 LookupResult* result) {
635 obj->LocalLookupRealNamedProperty(name, result);
636
637 if (!result->IsProperty()) {
638 Object* proto = obj->GetPrototype();
639 if (proto->IsJSObject() &&
640 JSObject::cast(proto)->map()->is_hidden_prototype())
641 GetOwnPropertyImplementation(JSObject::cast(proto),
642 name, result);
643 }
644}
645
646
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000647static bool CheckAccessException(LookupResult* result,
648 v8::AccessType access_type) {
649 if (result->type() == CALLBACKS) {
650 Object* callback = result->GetCallbackObject();
651 if (callback->IsAccessorInfo()) {
652 AccessorInfo* info = AccessorInfo::cast(callback);
653 bool can_access =
654 (access_type == v8::ACCESS_HAS &&
655 (info->all_can_read() || info->all_can_write())) ||
656 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
657 (access_type == v8::ACCESS_SET && info->all_can_write());
658 return can_access;
659 }
660 }
661
662 return false;
663}
664
665
666static bool CheckAccess(JSObject* obj,
667 String* name,
668 LookupResult* result,
669 v8::AccessType access_type) {
670 ASSERT(result->IsProperty());
671
672 JSObject* holder = result->holder();
673 JSObject* current = obj;
674 while (true) {
675 if (current->IsAccessCheckNeeded() &&
676 !Top::MayNamedAccess(current, name, access_type)) {
677 // Access check callback denied the access, but some properties
678 // can have a special permissions which override callbacks descision
679 // (currently see v8::AccessControl).
680 break;
681 }
682
683 if (current == holder) {
684 return true;
685 }
686
687 current = JSObject::cast(current->GetPrototype());
688 }
689
690 // API callbacks can have per callback access exceptions.
691 switch (result->type()) {
692 case CALLBACKS: {
693 if (CheckAccessException(result, access_type)) {
694 return true;
695 }
696 break;
697 }
698 case INTERCEPTOR: {
699 // If the object has an interceptor, try real named properties.
700 // Overwrite the result to fetch the correct property later.
701 holder->LookupRealNamedProperty(name, result);
702 if (result->IsProperty()) {
703 if (CheckAccessException(result, access_type)) {
704 return true;
705 }
706 }
707 break;
708 }
709 default:
710 break;
711 }
712
713 Top::ReportFailedAccessCheck(current, access_type);
714 return false;
715}
716
717
718// TODO(1095): we should traverse hidden prototype hierachy as well.
719static bool CheckElementAccess(JSObject* obj,
720 uint32_t index,
721 v8::AccessType access_type) {
722 if (obj->IsAccessCheckNeeded() &&
723 !Top::MayIndexedAccess(obj, index, access_type)) {
724 return false;
725 }
726
727 return true;
728}
729
730
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000731// Enumerator used as indices into the array returned from GetOwnProperty
732enum PropertyDescriptorIndices {
733 IS_ACCESSOR_INDEX,
734 VALUE_INDEX,
735 GETTER_INDEX,
736 SETTER_INDEX,
737 WRITABLE_INDEX,
738 ENUMERABLE_INDEX,
739 CONFIGURABLE_INDEX,
740 DESCRIPTOR_SIZE
741};
742
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000743// Returns an array with the property description:
744// if args[1] is not a property on args[0]
745// returns undefined
746// if args[1] is a data property on args[0]
747// [false, value, Writeable, Enumerable, Configurable]
748// if args[1] is an accessor on args[0]
749// [true, GetFunction, SetFunction, Enumerable, Configurable]
lrn@chromium.org303ada72010-10-27 09:33:13 +0000750static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000751 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000752 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000753 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000754 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
755 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000756 CONVERT_ARG_CHECKED(JSObject, obj, 0);
757 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000758
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000759 // This could be an element.
760 uint32_t index;
761 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000762 switch (obj->HasLocalElement(index)) {
763 case JSObject::UNDEFINED_ELEMENT:
764 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000765
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000766 case JSObject::STRING_CHARACTER_ELEMENT: {
767 // Special handling of string objects according to ECMAScript 5
768 // 15.5.5.2. Note that this might be a string object with elements
769 // other than the actual string value. This is covered by the
770 // subsequent cases.
771 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
772 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000773 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000774
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000775 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
776 elms->set(VALUE_INDEX, *substr);
777 elms->set(WRITABLE_INDEX, Heap::false_value());
778 elms->set(ENUMERABLE_INDEX, Heap::false_value());
779 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
780 return *desc;
781 }
782
783 case JSObject::INTERCEPTED_ELEMENT:
784 case JSObject::FAST_ELEMENT: {
785 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000786 elms->set(VALUE_INDEX, *GetElement(obj, index));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000787 elms->set(WRITABLE_INDEX, Heap::true_value());
788 elms->set(ENUMERABLE_INDEX, Heap::true_value());
789 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
790 return *desc;
791 }
792
793 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000794 Handle<JSObject> holder = obj;
795 if (obj->IsJSGlobalProxy()) {
796 Object* proto = obj->GetPrototype();
797 if (proto->IsNull()) return Heap::undefined_value();
798 ASSERT(proto->IsJSGlobalObject());
799 holder = Handle<JSObject>(JSObject::cast(proto));
800 }
801 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000802 int entry = dictionary->FindEntry(index);
803 ASSERT(entry != NumberDictionary::kNotFound);
804 PropertyDetails details = dictionary->DetailsAt(entry);
805 switch (details.type()) {
806 case CALLBACKS: {
807 // This is an accessor property with getter and/or setter.
808 FixedArray* callbacks =
809 FixedArray::cast(dictionary->ValueAt(entry));
810 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000811 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
812 elms->set(GETTER_INDEX, callbacks->get(0));
813 }
814 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
815 elms->set(SETTER_INDEX, callbacks->get(1));
816 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000817 break;
818 }
819 case NORMAL:
820 // This is a data property.
821 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000822 elms->set(VALUE_INDEX, *GetElement(obj, index));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000823 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
824 break;
825 default:
826 UNREACHABLE();
827 break;
828 }
829 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
830 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
831 return *desc;
832 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000833 }
834 }
835
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000836 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000837 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000838
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000839 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000840 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000841 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000842
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000843 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
844 return Heap::false_value();
845 }
846
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000847 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
848 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000849
850 bool is_js_accessor = (result.type() == CALLBACKS) &&
851 (result.GetCallbackObject()->IsFixedArray());
852
853 if (is_js_accessor) {
854 // __defineGetter__/__defineSetter__ callback.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000855 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000856
857 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
858 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
859 elms->set(GETTER_INDEX, structure->get(0));
860 }
861 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
862 elms->set(SETTER_INDEX, structure->get(1));
863 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000864 } else {
865 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
866 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
867
868 PropertyAttributes attrs;
869 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000870 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000871 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
872 if (!maybe_value->ToObject(&value)) return maybe_value;
873 }
874 elms->set(VALUE_INDEX, value);
875 }
876
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000877 return *desc;
878}
879
880
lrn@chromium.org303ada72010-10-27 09:33:13 +0000881static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000882 ASSERT(args.length() == 1);
883 CONVERT_CHECKED(JSObject, obj, args[0]);
884 return obj->PreventExtensions();
885}
886
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000887
lrn@chromium.org303ada72010-10-27 09:33:13 +0000888static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000889 ASSERT(args.length() == 1);
890 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000891 if (obj->IsJSGlobalProxy()) {
892 Object* proto = obj->GetPrototype();
893 if (proto->IsNull()) return Heap::false_value();
894 ASSERT(proto->IsJSGlobalObject());
895 obj = JSObject::cast(proto);
896 }
897 return obj->map()->is_extensible() ? Heap::true_value()
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000898 : Heap::false_value();
899}
900
901
lrn@chromium.org303ada72010-10-27 09:33:13 +0000902static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000903 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000904 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000905 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
906 CONVERT_ARG_CHECKED(String, pattern, 1);
907 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000908 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
909 if (result.is_null()) return Failure::Exception();
910 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911}
912
913
lrn@chromium.org303ada72010-10-27 09:33:13 +0000914static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000915 HandleScope scope;
916 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000917 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000918 return *Factory::CreateApiFunction(data);
919}
920
921
lrn@chromium.org303ada72010-10-27 09:33:13 +0000922static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923 ASSERT(args.length() == 1);
924 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000925 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926 return Heap::ToBoolean(result);
927}
928
929
lrn@chromium.org303ada72010-10-27 09:33:13 +0000930static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931 ASSERT(args.length() == 2);
932 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000934 int index = field->value();
935 int offset = index * kPointerSize + HeapObject::kHeaderSize;
936 InstanceType type = templ->map()->instance_type();
937 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
938 type == OBJECT_TEMPLATE_INFO_TYPE);
939 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000940 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000941 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
942 } else {
943 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
944 }
945 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000946}
947
948
lrn@chromium.org303ada72010-10-27 09:33:13 +0000949static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000950 ASSERT(args.length() == 1);
951 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000952 Map* old_map = object->map();
953 bool needs_access_checks = old_map->is_access_check_needed();
954 if (needs_access_checks) {
955 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000956 Object* new_map;
957 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
958 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
959 }
ager@chromium.org32912102009-01-16 10:38:43 +0000960
961 Map::cast(new_map)->set_is_access_check_needed(false);
962 object->set_map(Map::cast(new_map));
963 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000964 return needs_access_checks ? Heap::true_value() : Heap::false_value();
965}
966
967
lrn@chromium.org303ada72010-10-27 09:33:13 +0000968static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000969 ASSERT(args.length() == 1);
970 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000971 Map* old_map = object->map();
972 if (!old_map->is_access_check_needed()) {
973 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000974 Object* new_map;
975 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
976 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
977 }
ager@chromium.org32912102009-01-16 10:38:43 +0000978
979 Map::cast(new_map)->set_is_access_check_needed(true);
980 object->set_map(Map::cast(new_map));
981 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000982 return Heap::undefined_value();
983}
984
985
lrn@chromium.org303ada72010-10-27 09:33:13 +0000986static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000987 HandleScope scope;
988 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
989 Handle<Object> args[2] = { type_handle, name };
990 Handle<Object> error =
991 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
992 return Top::Throw(*error);
993}
994
995
lrn@chromium.org303ada72010-10-27 09:33:13 +0000996static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 HandleScope scope;
998 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
999
ager@chromium.org3811b432009-10-28 14:53:37 +00001000 Handle<Context> context = args.at<Context>(0);
1001 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002 bool is_eval = Smi::cast(args[2])->value() == 1;
1003
1004 // Compute the property attributes. According to ECMA-262, section
1005 // 13, page 71, the property must be read-only and
1006 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1007 // property as read-only, so we don't either.
1008 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1009
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 // Traverse the name/value pairs and set the properties.
1011 int length = pairs->length();
1012 for (int i = 0; i < length; i += 2) {
1013 HandleScope scope;
1014 Handle<String> name(String::cast(pairs->get(i)));
1015 Handle<Object> value(pairs->get(i + 1));
1016
1017 // We have to declare a global const property. To capture we only
1018 // assign to it when evaluating the assignment for "const x =
1019 // <expr>" the initial value is the hole.
1020 bool is_const_property = value->IsTheHole();
1021
1022 if (value->IsUndefined() || is_const_property) {
1023 // Lookup the property in the global object, and don't set the
1024 // value of the variable if the property is already there.
1025 LookupResult lookup;
1026 global->Lookup(*name, &lookup);
1027 if (lookup.IsProperty()) {
1028 // Determine if the property is local by comparing the holder
1029 // against the global object. The information will be used to
1030 // avoid throwing re-declaration errors when declaring
1031 // variables or constants that exist in the prototype chain.
1032 bool is_local = (*global == lookup.holder());
1033 // Get the property attributes and determine if the property is
1034 // read-only.
1035 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1036 bool is_read_only = (attributes & READ_ONLY) != 0;
1037 if (lookup.type() == INTERCEPTOR) {
1038 // If the interceptor says the property is there, we
1039 // just return undefined without overwriting the property.
1040 // Otherwise, we continue to setting the property.
1041 if (attributes != ABSENT) {
1042 // Check if the existing property conflicts with regards to const.
1043 if (is_local && (is_read_only || is_const_property)) {
1044 const char* type = (is_read_only) ? "const" : "var";
1045 return ThrowRedeclarationError(type, name);
1046 };
1047 // The property already exists without conflicting: Go to
1048 // the next declaration.
1049 continue;
1050 }
1051 // Fall-through and introduce the absent property by using
1052 // SetProperty.
1053 } else {
1054 if (is_local && (is_read_only || is_const_property)) {
1055 const char* type = (is_read_only) ? "const" : "var";
1056 return ThrowRedeclarationError(type, name);
1057 }
1058 // The property already exists without conflicting: Go to
1059 // the next declaration.
1060 continue;
1061 }
1062 }
1063 } else {
1064 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001065 Handle<SharedFunctionInfo> shared =
1066 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001067 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001068 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069 value = function;
1070 }
1071
1072 LookupResult lookup;
1073 global->LocalLookup(*name, &lookup);
1074
1075 PropertyAttributes attributes = is_const_property
1076 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1077 : base;
1078
1079 if (lookup.IsProperty()) {
1080 // There's a local property that we need to overwrite because
1081 // we're either declaring a function or there's an interceptor
1082 // that claims the property is absent.
1083
1084 // Check for conflicting re-declarations. We cannot have
1085 // conflicting types in case of intercepted properties because
1086 // they are absent.
1087 if (lookup.type() != INTERCEPTOR &&
1088 (lookup.IsReadOnly() || is_const_property)) {
1089 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
1090 return ThrowRedeclarationError(type, name);
1091 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001092 RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001093 } else {
1094 // If a property with this name does not already exist on the
1095 // global object add the property locally. We take special
1096 // precautions to always add it as a local property even in case
1097 // of callbacks in the prototype chain (this rules out using
1098 // SetProperty). Also, we must use the handle-based version to
1099 // avoid GC issues.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001100 RETURN_IF_EMPTY_HANDLE(
1101 SetLocalPropertyIgnoreAttributes(global, name, value, attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102 }
1103 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001104
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001105 ASSERT(!Top::has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106 return Heap::undefined_value();
1107}
1108
1109
lrn@chromium.org303ada72010-10-27 09:33:13 +00001110static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001112 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001113
ager@chromium.org7c537e22008-10-16 08:43:32 +00001114 CONVERT_ARG_CHECKED(Context, context, 0);
1115 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001116 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001117 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001118 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001119 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001120
1121 // Declarations are always done in the function context.
1122 context = Handle<Context>(context->fcontext());
1123
1124 int index;
1125 PropertyAttributes attributes;
1126 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001127 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001128 context->Lookup(name, flags, &index, &attributes);
1129
1130 if (attributes != ABSENT) {
1131 // The name was declared before; check for conflicting
1132 // re-declarations: This is similar to the code in parser.cc in
1133 // the AstBuildingParser::Declare function.
1134 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1135 // Functions are not read-only.
1136 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1137 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1138 return ThrowRedeclarationError(type, name);
1139 }
1140
1141 // Initialize it if necessary.
1142 if (*initial_value != NULL) {
1143 if (index >= 0) {
1144 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001145 // the function context or the arguments object.
1146 if (holder->IsContext()) {
1147 ASSERT(holder.is_identical_to(context));
1148 if (((attributes & READ_ONLY) == 0) ||
1149 context->get(index)->IsTheHole()) {
1150 context->set(index, *initial_value);
1151 }
1152 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001153 // The holder is an arguments object.
1154 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001155 Handle<Object> result = SetElement(arguments, index, initial_value);
1156 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001157 }
1158 } else {
1159 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001160 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001161 RETURN_IF_EMPTY_HANDLE(
1162 SetProperty(context_ext, name, initial_value, mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 }
1164 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001166 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001167 // The property is not in the function context. It needs to be
1168 // "declared" in the function context's extension context, or in the
1169 // global context.
1170 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001171 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001172 // The function context's extension context exists - use it.
1173 context_ext = Handle<JSObject>(context->extension());
1174 } else {
1175 // The function context's extension context does not exists - allocate
1176 // it.
1177 context_ext = Factory::NewJSObject(Top::context_extension_function());
1178 // And store it in the extension slot.
1179 context->set_extension(*context_ext);
1180 }
1181 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001182
ager@chromium.org7c537e22008-10-16 08:43:32 +00001183 // Declare the property by setting it to the initial value if provided,
1184 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1185 // constant declarations).
1186 ASSERT(!context_ext->HasLocalProperty(*name));
1187 Handle<Object> value(Heap::undefined_value());
1188 if (*initial_value != NULL) value = initial_value;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001189 RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, mode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001190 }
1191
1192 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193}
1194
1195
lrn@chromium.org303ada72010-10-27 09:33:13 +00001196static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 NoHandleAllocation nha;
1198
1199 // Determine if we need to assign to the variable if it already
1200 // exists (based on the number of arguments).
1201 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1202 bool assign = args.length() == 2;
1203
1204 CONVERT_ARG_CHECKED(String, name, 0);
1205 GlobalObject* global = Top::context()->global();
1206
1207 // According to ECMA-262, section 12.2, page 62, the property must
1208 // not be deletable.
1209 PropertyAttributes attributes = DONT_DELETE;
1210
1211 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001212 // there, there is a property with this name in the prototype chain.
1213 // We follow Safari and Firefox behavior and only set the property
1214 // locally if there is an explicit initialization value that we have
1215 // to assign to the property. When adding the property we take
1216 // special precautions to always add it as a local property even in
1217 // case of callbacks in the prototype chain (this rules out using
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001218 // SetProperty). We have SetLocalPropertyIgnoreAttributes for
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001219 // this.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001220 // Note that objects can have hidden prototypes, so we need to traverse
1221 // the whole chain of hidden prototypes to do a 'local' lookup.
1222 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001224 while (true) {
1225 real_holder->LocalLookup(*name, &lookup);
1226 if (lookup.IsProperty()) {
1227 // Determine if this is a redeclaration of something read-only.
1228 if (lookup.IsReadOnly()) {
1229 // If we found readonly property on one of hidden prototypes,
1230 // just shadow it.
1231 if (real_holder != Top::context()->global()) break;
1232 return ThrowRedeclarationError("const", name);
1233 }
1234
1235 // Determine if this is a redeclaration of an intercepted read-only
1236 // property and figure out if the property exists at all.
1237 bool found = true;
1238 PropertyType type = lookup.type();
1239 if (type == INTERCEPTOR) {
1240 HandleScope handle_scope;
1241 Handle<JSObject> holder(real_holder);
1242 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1243 real_holder = *holder;
1244 if (intercepted == ABSENT) {
1245 // The interceptor claims the property isn't there. We need to
1246 // make sure to introduce it.
1247 found = false;
1248 } else if ((intercepted & READ_ONLY) != 0) {
1249 // The property is present, but read-only. Since we're trying to
1250 // overwrite it with a variable declaration we must throw a
1251 // re-declaration error. However if we found readonly property
1252 // on one of hidden prototypes, just shadow it.
1253 if (real_holder != Top::context()->global()) break;
1254 return ThrowRedeclarationError("const", name);
1255 }
1256 }
1257
1258 if (found && !assign) {
1259 // The global property is there and we're not assigning any value
1260 // to it. Just return.
1261 return Heap::undefined_value();
1262 }
1263
1264 // Assign the value (or undefined) to the property.
1265 Object* value = (assign) ? args[1] : Heap::undefined_value();
1266 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001267 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001268
1269 Object* proto = real_holder->GetPrototype();
1270 if (!proto->IsJSObject())
1271 break;
1272
1273 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1274 break;
1275
1276 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 }
1278
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001279 global = Top::context()->global();
1280 if (assign) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001281 return global->SetLocalPropertyIgnoreAttributes(*name,
1282 args[1],
1283 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001285 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286}
1287
1288
lrn@chromium.org303ada72010-10-27 09:33:13 +00001289static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290 // All constants are declared with an initial value. The name
1291 // of the constant is the first argument and the initial value
1292 // is the second.
1293 RUNTIME_ASSERT(args.length() == 2);
1294 CONVERT_ARG_CHECKED(String, name, 0);
1295 Handle<Object> value = args.at<Object>(1);
1296
1297 // Get the current global object from top.
1298 GlobalObject* global = Top::context()->global();
1299
1300 // According to ECMA-262, section 12.2, page 62, the property must
1301 // not be deletable. Since it's a const, it must be READ_ONLY too.
1302 PropertyAttributes attributes =
1303 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1304
1305 // Lookup the property locally in the global object. If it isn't
1306 // there, we add the property and take special precautions to always
1307 // add it as a local property even in case of callbacks in the
1308 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001309 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310 LookupResult lookup;
1311 global->LocalLookup(*name, &lookup);
1312 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001313 return global->SetLocalPropertyIgnoreAttributes(*name,
1314 *value,
1315 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 }
1317
1318 // Determine if this is a redeclaration of something not
1319 // read-only. In case the result is hidden behind an interceptor we
1320 // need to ask it for the property attributes.
1321 if (!lookup.IsReadOnly()) {
1322 if (lookup.type() != INTERCEPTOR) {
1323 return ThrowRedeclarationError("var", name);
1324 }
1325
1326 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1327
1328 // Throw re-declaration error if the intercepted property is present
1329 // but not read-only.
1330 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1331 return ThrowRedeclarationError("var", name);
1332 }
1333
1334 // Restore global object from context (in case of GC) and continue
1335 // with setting the value because the property is either absent or
1336 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001337 HandleScope handle_scope;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001338 Handle<GlobalObject> global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001340 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341 // property through an interceptor and only do it if it's
1342 // uninitialized, e.g. the hole. Nirk...
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001343 RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344 return *value;
1345 }
1346
1347 // Set the value, but only we're assigning the initial value to a
1348 // constant. For now, we determine this by checking if the
1349 // current value is the hole.
1350 PropertyType type = lookup.type();
1351 if (type == FIELD) {
1352 FixedArray* properties = global->properties();
1353 int index = lookup.GetFieldIndex();
1354 if (properties->get(index)->IsTheHole()) {
1355 properties->set(index, *value);
1356 }
1357 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001358 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1359 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360 }
1361 } else {
1362 // Ignore re-initialization of constants that have already been
1363 // assigned a function value.
1364 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1365 }
1366
1367 // Use the set value as the result of the operation.
1368 return *value;
1369}
1370
1371
lrn@chromium.org303ada72010-10-27 09:33:13 +00001372static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001373 HandleScope scope;
1374 ASSERT(args.length() == 3);
1375
1376 Handle<Object> value(args[0]);
1377 ASSERT(!value->IsTheHole());
1378 CONVERT_ARG_CHECKED(Context, context, 1);
1379 Handle<String> name(String::cast(args[2]));
1380
1381 // Initializations are always done in the function context.
1382 context = Handle<Context>(context->fcontext());
1383
1384 int index;
1385 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001386 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001387 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001388 context->Lookup(name, flags, &index, &attributes);
1389
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001390 // In most situations, the property introduced by the const
1391 // declaration should be present in the context extension object.
1392 // However, because declaration and initialization are separate, the
1393 // property might have been deleted (if it was introduced by eval)
1394 // before we reach the initialization point.
1395 //
1396 // Example:
1397 //
1398 // function f() { eval("delete x; const x;"); }
1399 //
1400 // In that case, the initialization behaves like a normal assignment
1401 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001403 // Property was found in a context.
1404 if (holder->IsContext()) {
1405 // The holder cannot be the function context. If it is, there
1406 // should have been a const redeclaration error when declaring
1407 // the const property.
1408 ASSERT(!holder.is_identical_to(context));
1409 if ((attributes & READ_ONLY) == 0) {
1410 Handle<Context>::cast(holder)->set(index, *value);
1411 }
1412 } else {
1413 // The holder is an arguments object.
1414 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001415 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1416 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417 }
1418 return *value;
1419 }
1420
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001421 // The property could not be found, we introduce it in the global
1422 // context.
1423 if (attributes == ABSENT) {
1424 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001425 RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, NONE));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001426 return *value;
1427 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001428
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001429 // The property was present in a context extension object.
1430 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001431
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001432 if (*context_ext == context->extension()) {
1433 // This is the property that was introduced by the const
1434 // declaration. Set it if it hasn't been set before. NOTE: We
1435 // cannot use GetProperty() to get the current value as it
1436 // 'unholes' the value.
1437 LookupResult lookup;
1438 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1439 ASSERT(lookup.IsProperty()); // the property was declared
1440 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1441
1442 PropertyType type = lookup.type();
1443 if (type == FIELD) {
1444 FixedArray* properties = context_ext->properties();
1445 int index = lookup.GetFieldIndex();
1446 if (properties->get(index)->IsTheHole()) {
1447 properties->set(index, *value);
1448 }
1449 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001450 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1451 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001452 }
1453 } else {
1454 // We should not reach here. Any real, named property should be
1455 // either a field or a dictionary slot.
1456 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001457 }
1458 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001459 // The property was found in a different context extension object.
1460 // Set it if it is not a read-only property.
1461 if ((attributes & READ_ONLY) == 0) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001462 RETURN_IF_EMPTY_HANDLE(
1463 SetProperty(context_ext, name, value, attributes));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001464 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001465 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001466
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467 return *value;
1468}
1469
1470
lrn@chromium.org303ada72010-10-27 09:33:13 +00001471static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001472 Arguments args) {
1473 HandleScope scope;
1474 ASSERT(args.length() == 2);
1475 CONVERT_ARG_CHECKED(JSObject, object, 0);
1476 CONVERT_SMI_CHECKED(properties, args[1]);
1477 if (object->HasFastProperties()) {
1478 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1479 }
1480 return *object;
1481}
1482
1483
lrn@chromium.org303ada72010-10-27 09:33:13 +00001484static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001485 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001486 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001487 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1488 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001489 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001490 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001491 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001492 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001493 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001494 RUNTIME_ASSERT(index >= 0);
1495 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001496 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001497 Handle<Object> result = RegExpImpl::Exec(regexp,
1498 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001499 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001500 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001501 if (result.is_null()) return Failure::Exception();
1502 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001503}
1504
1505
lrn@chromium.org303ada72010-10-27 09:33:13 +00001506static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001507 ASSERT(args.length() == 3);
1508 CONVERT_SMI_CHECKED(elements_count, args[0]);
1509 if (elements_count > JSArray::kMaxFastElementsLength) {
1510 return Top::ThrowIllegalOperation();
1511 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001512 Object* new_object;
1513 { MaybeObject* maybe_new_object =
1514 Heap::AllocateFixedArrayWithHoles(elements_count);
1515 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1516 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001517 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001518 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1519 NEW_SPACE,
1520 OLD_POINTER_SPACE);
1521 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1522 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001523 {
1524 AssertNoAllocation no_gc;
1525 HandleScope scope;
1526 reinterpret_cast<HeapObject*>(new_object)->
1527 set_map(Top::global_context()->regexp_result_map());
1528 }
1529 JSArray* array = JSArray::cast(new_object);
1530 array->set_properties(Heap::empty_fixed_array());
1531 array->set_elements(elements);
1532 array->set_length(Smi::FromInt(elements_count));
1533 // Write in-object properties after the length of the array.
1534 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1535 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1536 return array;
1537}
1538
1539
lrn@chromium.org303ada72010-10-27 09:33:13 +00001540static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001541 AssertNoAllocation no_alloc;
1542 ASSERT(args.length() == 5);
1543 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1544 CONVERT_CHECKED(String, source, args[1]);
1545
1546 Object* global = args[2];
1547 if (!global->IsTrue()) global = Heap::false_value();
1548
1549 Object* ignoreCase = args[3];
1550 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1551
1552 Object* multiline = args[4];
1553 if (!multiline->IsTrue()) multiline = Heap::false_value();
1554
1555 Map* map = regexp->map();
1556 Object* constructor = map->constructor();
1557 if (constructor->IsJSFunction() &&
1558 JSFunction::cast(constructor)->initial_map() == map) {
1559 // If we still have the original map, set in-object properties directly.
1560 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1561 // TODO(lrn): Consider skipping write barrier on booleans as well.
1562 // Both true and false should be in oldspace at all times.
1563 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1564 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1565 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1566 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1567 Smi::FromInt(0),
1568 SKIP_WRITE_BARRIER);
1569 return regexp;
1570 }
1571
lrn@chromium.org303ada72010-10-27 09:33:13 +00001572 // Map has changed, so use generic, but slower, method. Since these
1573 // properties were all added as DONT_DELETE they must be present and
1574 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001575 PropertyAttributes final =
1576 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1577 PropertyAttributes writable =
1578 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001579 MaybeObject* result;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001580 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
1581 source,
1582 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001583 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001584 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
1585 global,
1586 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001587 ASSERT(!result->IsFailure());
1588 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001589 regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
1590 ignoreCase,
1591 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001592 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001593 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
1594 multiline,
1595 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001596 ASSERT(!result->IsFailure());
1597 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001598 regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
1599 Smi::FromInt(0),
1600 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001601 ASSERT(!result->IsFailure());
1602 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001603 return regexp;
1604}
1605
1606
lrn@chromium.org303ada72010-10-27 09:33:13 +00001607static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001608 HandleScope scope;
1609 ASSERT(args.length() == 1);
1610 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1611 // This is necessary to enable fast checks for absence of elements
1612 // on Array.prototype and below.
1613 prototype->set_elements(Heap::empty_fixed_array());
1614 return Smi::FromInt(0);
1615}
1616
1617
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001618static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1619 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001620 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001621 Handle<String> key = Factory::LookupAsciiSymbol(name);
1622 Handle<Code> code(Builtins::builtin(builtin_name));
1623 Handle<JSFunction> optimized = Factory::NewFunction(key,
1624 JS_OBJECT_TYPE,
1625 JSObject::kHeaderSize,
1626 code,
1627 false);
1628 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001629 SetProperty(holder, key, optimized, NONE);
1630 return optimized;
1631}
1632
1633
lrn@chromium.org303ada72010-10-27 09:33:13 +00001634static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001635 HandleScope scope;
1636 ASSERT(args.length() == 1);
1637 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1638
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001639 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1640 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001641 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1642 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1643 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1644 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001645 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001646
1647 return *holder;
1648}
1649
1650
lrn@chromium.org303ada72010-10-27 09:33:13 +00001651static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001652 // Returns a real global receiver, not one of builtins object.
1653 Context* global_context = Top::context()->global()->global_context();
1654 return global_context->global()->global_receiver();
1655}
1656
1657
lrn@chromium.org303ada72010-10-27 09:33:13 +00001658static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001659 HandleScope scope;
1660 ASSERT(args.length() == 4);
1661 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1662 int index = Smi::cast(args[1])->value();
1663 Handle<String> pattern = args.at<String>(2);
1664 Handle<String> flags = args.at<String>(3);
1665
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001666 // Get the RegExp function from the context in the literals array.
1667 // This is the RegExp function from the context in which the
1668 // function was created. We do not use the RegExp function from the
1669 // current global context because this might be the RegExp function
1670 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001671 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001672 Handle<JSFunction>(
1673 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001674 // Compute the regular expression literal.
1675 bool has_pending_exception;
1676 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001677 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1678 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001679 if (has_pending_exception) {
1680 ASSERT(Top::has_pending_exception());
1681 return Failure::Exception();
1682 }
1683 literals->set(index, *regexp);
1684 return *regexp;
1685}
1686
1687
lrn@chromium.org303ada72010-10-27 09:33:13 +00001688static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689 NoHandleAllocation ha;
1690 ASSERT(args.length() == 1);
1691
1692 CONVERT_CHECKED(JSFunction, f, args[0]);
1693 return f->shared()->name();
1694}
1695
1696
lrn@chromium.org303ada72010-10-27 09:33:13 +00001697static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001698 NoHandleAllocation ha;
1699 ASSERT(args.length() == 2);
1700
1701 CONVERT_CHECKED(JSFunction, f, args[0]);
1702 CONVERT_CHECKED(String, name, args[1]);
1703 f->shared()->set_name(name);
1704 return Heap::undefined_value();
1705}
1706
1707
lrn@chromium.org303ada72010-10-27 09:33:13 +00001708static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001709 NoHandleAllocation ha;
1710 ASSERT(args.length() == 1);
1711
1712 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001713 Object* obj;
1714 { MaybeObject* maybe_obj = f->RemovePrototype();
1715 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1716 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001717
1718 return Heap::undefined_value();
1719}
1720
1721
lrn@chromium.org303ada72010-10-27 09:33:13 +00001722static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001723 HandleScope scope;
1724 ASSERT(args.length() == 1);
1725
1726 CONVERT_CHECKED(JSFunction, fun, args[0]);
1727 Handle<Object> script = Handle<Object>(fun->shared()->script());
1728 if (!script->IsScript()) return Heap::undefined_value();
1729
1730 return *GetScriptWrapper(Handle<Script>::cast(script));
1731}
1732
1733
lrn@chromium.org303ada72010-10-27 09:33:13 +00001734static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001735 NoHandleAllocation ha;
1736 ASSERT(args.length() == 1);
1737
1738 CONVERT_CHECKED(JSFunction, f, args[0]);
1739 return f->shared()->GetSourceCode();
1740}
1741
1742
lrn@chromium.org303ada72010-10-27 09:33:13 +00001743static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001744 NoHandleAllocation ha;
1745 ASSERT(args.length() == 1);
1746
1747 CONVERT_CHECKED(JSFunction, fun, args[0]);
1748 int pos = fun->shared()->start_position();
1749 return Smi::FromInt(pos);
1750}
1751
1752
lrn@chromium.org303ada72010-10-27 09:33:13 +00001753static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001754 ASSERT(args.length() == 2);
1755
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001756 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001757 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1758
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001759 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1760
1761 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001762 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001763}
1764
1765
1766
lrn@chromium.org303ada72010-10-27 09:33:13 +00001767static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001768 NoHandleAllocation ha;
1769 ASSERT(args.length() == 2);
1770
1771 CONVERT_CHECKED(JSFunction, fun, args[0]);
1772 CONVERT_CHECKED(String, name, args[1]);
1773 fun->SetInstanceClassName(name);
1774 return Heap::undefined_value();
1775}
1776
1777
lrn@chromium.org303ada72010-10-27 09:33:13 +00001778static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001779 NoHandleAllocation ha;
1780 ASSERT(args.length() == 2);
1781
1782 CONVERT_CHECKED(JSFunction, fun, args[0]);
1783 CONVERT_CHECKED(Smi, length, args[1]);
1784 fun->shared()->set_length(length->value());
1785 return length;
1786}
1787
1788
lrn@chromium.org303ada72010-10-27 09:33:13 +00001789static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001790 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001791 ASSERT(args.length() == 2);
1792
1793 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001794 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001795 Object* obj;
1796 { MaybeObject* maybe_obj =
1797 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1798 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1799 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001800 return args[0]; // return TOS
1801}
1802
1803
lrn@chromium.org303ada72010-10-27 09:33:13 +00001804static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001805 NoHandleAllocation ha;
1806 ASSERT(args.length() == 1);
1807
1808 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001809 return f->shared()->IsApiFunction() ? Heap::true_value()
1810 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001811}
1812
lrn@chromium.org303ada72010-10-27 09:33:13 +00001813static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001814 NoHandleAllocation ha;
1815 ASSERT(args.length() == 1);
1816
1817 CONVERT_CHECKED(JSFunction, f, args[0]);
1818 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1819}
1820
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001821
lrn@chromium.org303ada72010-10-27 09:33:13 +00001822static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001823 HandleScope scope;
1824 ASSERT(args.length() == 2);
1825
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001826 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001827 Handle<Object> code = args.at<Object>(1);
1828
1829 Handle<Context> context(target->context());
1830
1831 if (!code->IsNull()) {
1832 RUNTIME_ASSERT(code->IsJSFunction());
1833 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001834 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001835
1836 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001837 return Failure::Exception();
1838 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001839 // Since we don't store the source for this we should never
1840 // optimize this.
1841 shared->code()->set_optimizable(false);
1842
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001843 // Set the code, scope info, formal parameter count,
1844 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001845 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001846 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001847 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001848 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001849 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001850 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001851 // Set the source code of the target function to undefined.
1852 // SetCode is only used for built-in constructors like String,
1853 // Array, and Object, and some web code
1854 // doesn't like seeing source code for constructors.
1855 target->shared()->set_script(Heap::undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001856 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001857 // Clear the optimization hints related to the compiled code as these are no
1858 // longer valid when the code is overwritten.
1859 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001860 context = Handle<Context>(fun->context());
1861
1862 // Make sure we get a fresh copy of the literal vector to avoid
1863 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001864 int number_of_literals = fun->NumberOfLiterals();
1865 Handle<FixedArray> literals =
1866 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001867 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001868 // Insert the object, regexp and array functions in the literals
1869 // array prefix. These are the functions that will be used when
1870 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001871 literals->set(JSFunction::kLiteralGlobalContextIndex,
1872 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001873 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001874 // It's okay to skip the write barrier here because the literals
1875 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001876 target->set_literals(*literals, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001877 target->set_next_function_link(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001878 }
1879
1880 target->set_context(*context);
1881 return *target;
1882}
1883
1884
lrn@chromium.org303ada72010-10-27 09:33:13 +00001885static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001886 HandleScope scope;
1887 ASSERT(args.length() == 2);
1888 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1889 CONVERT_SMI_CHECKED(num, args[1]);
1890 RUNTIME_ASSERT(num >= 0);
1891 SetExpectedNofProperties(function, num);
1892 return Heap::undefined_value();
1893}
1894
1895
lrn@chromium.org303ada72010-10-27 09:33:13 +00001896MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001897 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001898 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001899 if (code <= 0xffff) {
1900 return Heap::LookupSingleCharacterStringFromCode(code);
1901 }
1902 }
1903 return Heap::empty_string();
1904}
1905
1906
lrn@chromium.org303ada72010-10-27 09:33:13 +00001907static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001908 NoHandleAllocation ha;
1909 ASSERT(args.length() == 2);
1910
1911 CONVERT_CHECKED(String, subject, args[0]);
1912 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001913 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001914
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001915 uint32_t i = 0;
1916 if (index->IsSmi()) {
1917 int value = Smi::cast(index)->value();
1918 if (value < 0) return Heap::nan_value();
1919 i = value;
1920 } else {
1921 ASSERT(index->IsHeapNumber());
1922 double value = HeapNumber::cast(index)->value();
1923 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001924 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001925
1926 // Flatten the string. If someone wants to get a char at an index
1927 // in a cons string, it is likely that more indices will be
1928 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001929 Object* flat;
1930 { MaybeObject* maybe_flat = subject->TryFlatten();
1931 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1932 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001933 subject = String::cast(flat);
1934
1935 if (i >= static_cast<uint32_t>(subject->length())) {
1936 return Heap::nan_value();
1937 }
1938
1939 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001940}
1941
1942
lrn@chromium.org303ada72010-10-27 09:33:13 +00001943static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001944 NoHandleAllocation ha;
1945 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001946 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001947}
1948
lrn@chromium.org25156de2010-04-06 13:10:27 +00001949
1950class FixedArrayBuilder {
1951 public:
1952 explicit FixedArrayBuilder(int initial_capacity)
1953 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1954 length_(0) {
1955 // Require a non-zero initial size. Ensures that doubling the size to
1956 // extend the array will work.
1957 ASSERT(initial_capacity > 0);
1958 }
1959
1960 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1961 : array_(backing_store),
1962 length_(0) {
1963 // Require a non-zero initial size. Ensures that doubling the size to
1964 // extend the array will work.
1965 ASSERT(backing_store->length() > 0);
1966 }
1967
1968 bool HasCapacity(int elements) {
1969 int length = array_->length();
1970 int required_length = length_ + elements;
1971 return (length >= required_length);
1972 }
1973
1974 void EnsureCapacity(int elements) {
1975 int length = array_->length();
1976 int required_length = length_ + elements;
1977 if (length < required_length) {
1978 int new_length = length;
1979 do {
1980 new_length *= 2;
1981 } while (new_length < required_length);
1982 Handle<FixedArray> extended_array =
1983 Factory::NewFixedArrayWithHoles(new_length);
1984 array_->CopyTo(0, *extended_array, 0, length_);
1985 array_ = extended_array;
1986 }
1987 }
1988
1989 void Add(Object* value) {
1990 ASSERT(length_ < capacity());
1991 array_->set(length_, value);
1992 length_++;
1993 }
1994
1995 void Add(Smi* value) {
1996 ASSERT(length_ < capacity());
1997 array_->set(length_, value);
1998 length_++;
1999 }
2000
2001 Handle<FixedArray> array() {
2002 return array_;
2003 }
2004
2005 int length() {
2006 return length_;
2007 }
2008
2009 int capacity() {
2010 return array_->length();
2011 }
2012
2013 Handle<JSArray> ToJSArray() {
2014 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
2015 result_array->set_length(Smi::FromInt(length_));
2016 return result_array;
2017 }
2018
2019 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2020 target_array->set_elements(*array_);
2021 target_array->set_length(Smi::FromInt(length_));
2022 return target_array;
2023 }
2024
2025 private:
2026 Handle<FixedArray> array_;
2027 int length_;
2028};
2029
2030
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002031// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002032const int kStringBuilderConcatHelperLengthBits = 11;
2033const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002034
2035template <typename schar>
2036static inline void StringBuilderConcatHelper(String*,
2037 schar*,
2038 FixedArray*,
2039 int);
2040
lrn@chromium.org25156de2010-04-06 13:10:27 +00002041typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2042 StringBuilderSubstringLength;
2043typedef BitField<int,
2044 kStringBuilderConcatHelperLengthBits,
2045 kStringBuilderConcatHelperPositionBits>
2046 StringBuilderSubstringPosition;
2047
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002048
2049class ReplacementStringBuilder {
2050 public:
2051 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00002052 : array_builder_(estimated_part_count),
2053 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002054 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002055 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002056 // Require a non-zero initial size. Ensures that doubling the size to
2057 // extend the array will work.
2058 ASSERT(estimated_part_count > 0);
2059 }
2060
lrn@chromium.org25156de2010-04-06 13:10:27 +00002061 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2062 int from,
2063 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002064 ASSERT(from >= 0);
2065 int length = to - from;
2066 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002067 if (StringBuilderSubstringLength::is_valid(length) &&
2068 StringBuilderSubstringPosition::is_valid(from)) {
2069 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2070 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002071 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002072 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002073 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002074 builder->Add(Smi::FromInt(-length));
2075 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002076 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002077 }
2078
2079
2080 void EnsureCapacity(int elements) {
2081 array_builder_.EnsureCapacity(elements);
2082 }
2083
2084
2085 void AddSubjectSlice(int from, int to) {
2086 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002087 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002088 }
2089
2090
2091 void AddString(Handle<String> string) {
2092 int length = string->length();
2093 ASSERT(length > 0);
2094 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002095 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002096 is_ascii_ = false;
2097 }
2098 IncrementCharacterCount(length);
2099 }
2100
2101
2102 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002103 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002104 return Factory::empty_string();
2105 }
2106
2107 Handle<String> joined_string;
2108 if (is_ascii_) {
2109 joined_string = NewRawAsciiString(character_count_);
2110 AssertNoAllocation no_alloc;
2111 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2112 char* char_buffer = seq->GetChars();
2113 StringBuilderConcatHelper(*subject_,
2114 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002115 *array_builder_.array(),
2116 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002117 } else {
2118 // Non-ASCII.
2119 joined_string = NewRawTwoByteString(character_count_);
2120 AssertNoAllocation no_alloc;
2121 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2122 uc16* char_buffer = seq->GetChars();
2123 StringBuilderConcatHelper(*subject_,
2124 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002125 *array_builder_.array(),
2126 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002127 }
2128 return joined_string;
2129 }
2130
2131
2132 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002133 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002134 V8::FatalProcessOutOfMemory("String.replace result too large.");
2135 }
2136 character_count_ += by;
2137 }
2138
lrn@chromium.org25156de2010-04-06 13:10:27 +00002139 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002140 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002141 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002142
lrn@chromium.org25156de2010-04-06 13:10:27 +00002143 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002144 Handle<String> NewRawAsciiString(int size) {
2145 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2146 }
2147
2148
2149 Handle<String> NewRawTwoByteString(int size) {
2150 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2151 }
2152
2153
2154 void AddElement(Object* element) {
2155 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002156 ASSERT(array_builder_.capacity() > array_builder_.length());
2157 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002158 }
2159
lrn@chromium.org25156de2010-04-06 13:10:27 +00002160 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002161 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002162 int character_count_;
2163 bool is_ascii_;
2164};
2165
2166
2167class CompiledReplacement {
2168 public:
2169 CompiledReplacement()
2170 : parts_(1), replacement_substrings_(0) {}
2171
2172 void Compile(Handle<String> replacement,
2173 int capture_count,
2174 int subject_length);
2175
2176 void Apply(ReplacementStringBuilder* builder,
2177 int match_from,
2178 int match_to,
2179 Handle<JSArray> last_match_info);
2180
2181 // Number of distinct parts of the replacement pattern.
2182 int parts() {
2183 return parts_.length();
2184 }
2185 private:
2186 enum PartType {
2187 SUBJECT_PREFIX = 1,
2188 SUBJECT_SUFFIX,
2189 SUBJECT_CAPTURE,
2190 REPLACEMENT_SUBSTRING,
2191 REPLACEMENT_STRING,
2192
2193 NUMBER_OF_PART_TYPES
2194 };
2195
2196 struct ReplacementPart {
2197 static inline ReplacementPart SubjectMatch() {
2198 return ReplacementPart(SUBJECT_CAPTURE, 0);
2199 }
2200 static inline ReplacementPart SubjectCapture(int capture_index) {
2201 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2202 }
2203 static inline ReplacementPart SubjectPrefix() {
2204 return ReplacementPart(SUBJECT_PREFIX, 0);
2205 }
2206 static inline ReplacementPart SubjectSuffix(int subject_length) {
2207 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2208 }
2209 static inline ReplacementPart ReplacementString() {
2210 return ReplacementPart(REPLACEMENT_STRING, 0);
2211 }
2212 static inline ReplacementPart ReplacementSubString(int from, int to) {
2213 ASSERT(from >= 0);
2214 ASSERT(to > from);
2215 return ReplacementPart(-from, to);
2216 }
2217
2218 // If tag <= 0 then it is the negation of a start index of a substring of
2219 // the replacement pattern, otherwise it's a value from PartType.
2220 ReplacementPart(int tag, int data)
2221 : tag(tag), data(data) {
2222 // Must be non-positive or a PartType value.
2223 ASSERT(tag < NUMBER_OF_PART_TYPES);
2224 }
2225 // Either a value of PartType or a non-positive number that is
2226 // the negation of an index into the replacement string.
2227 int tag;
2228 // The data value's interpretation depends on the value of tag:
2229 // tag == SUBJECT_PREFIX ||
2230 // tag == SUBJECT_SUFFIX: data is unused.
2231 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2232 // tag == REPLACEMENT_SUBSTRING ||
2233 // tag == REPLACEMENT_STRING: data is index into array of substrings
2234 // of the replacement string.
2235 // tag <= 0: Temporary representation of the substring of the replacement
2236 // string ranging over -tag .. data.
2237 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2238 // substring objects.
2239 int data;
2240 };
2241
2242 template<typename Char>
2243 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2244 Vector<Char> characters,
2245 int capture_count,
2246 int subject_length) {
2247 int length = characters.length();
2248 int last = 0;
2249 for (int i = 0; i < length; i++) {
2250 Char c = characters[i];
2251 if (c == '$') {
2252 int next_index = i + 1;
2253 if (next_index == length) { // No next character!
2254 break;
2255 }
2256 Char c2 = characters[next_index];
2257 switch (c2) {
2258 case '$':
2259 if (i > last) {
2260 // There is a substring before. Include the first "$".
2261 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2262 last = next_index + 1; // Continue after the second "$".
2263 } else {
2264 // Let the next substring start with the second "$".
2265 last = next_index;
2266 }
2267 i = next_index;
2268 break;
2269 case '`':
2270 if (i > last) {
2271 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2272 }
2273 parts->Add(ReplacementPart::SubjectPrefix());
2274 i = next_index;
2275 last = i + 1;
2276 break;
2277 case '\'':
2278 if (i > last) {
2279 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2280 }
2281 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2282 i = next_index;
2283 last = i + 1;
2284 break;
2285 case '&':
2286 if (i > last) {
2287 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2288 }
2289 parts->Add(ReplacementPart::SubjectMatch());
2290 i = next_index;
2291 last = i + 1;
2292 break;
2293 case '0':
2294 case '1':
2295 case '2':
2296 case '3':
2297 case '4':
2298 case '5':
2299 case '6':
2300 case '7':
2301 case '8':
2302 case '9': {
2303 int capture_ref = c2 - '0';
2304 if (capture_ref > capture_count) {
2305 i = next_index;
2306 continue;
2307 }
2308 int second_digit_index = next_index + 1;
2309 if (second_digit_index < length) {
2310 // Peek ahead to see if we have two digits.
2311 Char c3 = characters[second_digit_index];
2312 if ('0' <= c3 && c3 <= '9') { // Double digits.
2313 int double_digit_ref = capture_ref * 10 + c3 - '0';
2314 if (double_digit_ref <= capture_count) {
2315 next_index = second_digit_index;
2316 capture_ref = double_digit_ref;
2317 }
2318 }
2319 }
2320 if (capture_ref > 0) {
2321 if (i > last) {
2322 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2323 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002324 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002325 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2326 last = next_index + 1;
2327 }
2328 i = next_index;
2329 break;
2330 }
2331 default:
2332 i = next_index;
2333 break;
2334 }
2335 }
2336 }
2337 if (length > last) {
2338 if (last == 0) {
2339 parts->Add(ReplacementPart::ReplacementString());
2340 } else {
2341 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2342 }
2343 }
2344 }
2345
2346 ZoneList<ReplacementPart> parts_;
2347 ZoneList<Handle<String> > replacement_substrings_;
2348};
2349
2350
2351void CompiledReplacement::Compile(Handle<String> replacement,
2352 int capture_count,
2353 int subject_length) {
2354 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002355 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002356 AssertNoAllocation no_alloc;
2357 ParseReplacementPattern(&parts_,
2358 replacement->ToAsciiVector(),
2359 capture_count,
2360 subject_length);
2361 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002362 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002363 AssertNoAllocation no_alloc;
2364
2365 ParseReplacementPattern(&parts_,
2366 replacement->ToUC16Vector(),
2367 capture_count,
2368 subject_length);
2369 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002370 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002371 int substring_index = 0;
2372 for (int i = 0, n = parts_.length(); i < n; i++) {
2373 int tag = parts_[i].tag;
2374 if (tag <= 0) { // A replacement string slice.
2375 int from = -tag;
2376 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002377 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002378 parts_[i].tag = REPLACEMENT_SUBSTRING;
2379 parts_[i].data = substring_index;
2380 substring_index++;
2381 } else if (tag == REPLACEMENT_STRING) {
2382 replacement_substrings_.Add(replacement);
2383 parts_[i].data = substring_index;
2384 substring_index++;
2385 }
2386 }
2387}
2388
2389
2390void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2391 int match_from,
2392 int match_to,
2393 Handle<JSArray> last_match_info) {
2394 for (int i = 0, n = parts_.length(); i < n; i++) {
2395 ReplacementPart part = parts_[i];
2396 switch (part.tag) {
2397 case SUBJECT_PREFIX:
2398 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2399 break;
2400 case SUBJECT_SUFFIX: {
2401 int subject_length = part.data;
2402 if (match_to < subject_length) {
2403 builder->AddSubjectSlice(match_to, subject_length);
2404 }
2405 break;
2406 }
2407 case SUBJECT_CAPTURE: {
2408 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002409 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002410 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2411 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2412 if (from >= 0 && to > from) {
2413 builder->AddSubjectSlice(from, to);
2414 }
2415 break;
2416 }
2417 case REPLACEMENT_SUBSTRING:
2418 case REPLACEMENT_STRING:
2419 builder->AddString(replacement_substrings_[part.data]);
2420 break;
2421 default:
2422 UNREACHABLE();
2423 }
2424 }
2425}
2426
2427
2428
lrn@chromium.org303ada72010-10-27 09:33:13 +00002429MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2430 String* subject,
2431 JSRegExp* regexp,
2432 String* replacement,
2433 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002434 ASSERT(subject->IsFlat());
2435 ASSERT(replacement->IsFlat());
2436
2437 HandleScope handles;
2438
2439 int length = subject->length();
2440 Handle<String> subject_handle(subject);
2441 Handle<JSRegExp> regexp_handle(regexp);
2442 Handle<String> replacement_handle(replacement);
2443 Handle<JSArray> last_match_info_handle(last_match_info);
2444 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2445 subject_handle,
2446 0,
2447 last_match_info_handle);
2448 if (match.is_null()) {
2449 return Failure::Exception();
2450 }
2451 if (match->IsNull()) {
2452 return *subject_handle;
2453 }
2454
2455 int capture_count = regexp_handle->CaptureCount();
2456
2457 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002458 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002459 CompiledReplacement compiled_replacement;
2460 compiled_replacement.Compile(replacement_handle,
2461 capture_count,
2462 length);
2463
2464 bool is_global = regexp_handle->GetFlags().is_global();
2465
2466 // Guessing the number of parts that the final result string is built
2467 // from. Global regexps can match any number of times, so we guess
2468 // conservatively.
2469 int expected_parts =
2470 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2471 ReplacementStringBuilder builder(subject_handle, expected_parts);
2472
2473 // Index of end of last match.
2474 int prev = 0;
2475
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002476 // Number of parts added by compiled replacement plus preceeding
2477 // string and possibly suffix after last match. It is possible for
2478 // all components to use two elements when encoded as two smis.
2479 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002480 bool matched = true;
2481 do {
2482 ASSERT(last_match_info_handle->HasFastElements());
2483 // Increase the capacity of the builder before entering local handle-scope,
2484 // so its internal buffer can safely allocate a new handle if it grows.
2485 builder.EnsureCapacity(parts_added_per_loop);
2486
2487 HandleScope loop_scope;
2488 int start, end;
2489 {
2490 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002491 FixedArray* match_info_array =
2492 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002493
2494 ASSERT_EQ(capture_count * 2 + 2,
2495 RegExpImpl::GetLastCaptureCount(match_info_array));
2496 start = RegExpImpl::GetCapture(match_info_array, 0);
2497 end = RegExpImpl::GetCapture(match_info_array, 1);
2498 }
2499
2500 if (prev < start) {
2501 builder.AddSubjectSlice(prev, start);
2502 }
2503 compiled_replacement.Apply(&builder,
2504 start,
2505 end,
2506 last_match_info_handle);
2507 prev = end;
2508
2509 // Only continue checking for global regexps.
2510 if (!is_global) break;
2511
2512 // Continue from where the match ended, unless it was an empty match.
2513 int next = end;
2514 if (start == end) {
2515 next = end + 1;
2516 if (next > length) break;
2517 }
2518
2519 match = RegExpImpl::Exec(regexp_handle,
2520 subject_handle,
2521 next,
2522 last_match_info_handle);
2523 if (match.is_null()) {
2524 return Failure::Exception();
2525 }
2526 matched = !match->IsNull();
2527 } while (matched);
2528
2529 if (prev < length) {
2530 builder.AddSubjectSlice(prev, length);
2531 }
2532
2533 return *(builder.ToString());
2534}
2535
2536
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002537template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002538MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2539 String* subject,
2540 JSRegExp* regexp,
2541 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002542 ASSERT(subject->IsFlat());
2543
2544 HandleScope handles;
2545
2546 Handle<String> subject_handle(subject);
2547 Handle<JSRegExp> regexp_handle(regexp);
2548 Handle<JSArray> last_match_info_handle(last_match_info);
2549 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2550 subject_handle,
2551 0,
2552 last_match_info_handle);
2553 if (match.is_null()) return Failure::Exception();
2554 if (match->IsNull()) return *subject_handle;
2555
2556 ASSERT(last_match_info_handle->HasFastElements());
2557
2558 HandleScope loop_scope;
2559 int start, end;
2560 {
2561 AssertNoAllocation match_info_array_is_not_in_a_handle;
2562 FixedArray* match_info_array =
2563 FixedArray::cast(last_match_info_handle->elements());
2564
2565 start = RegExpImpl::GetCapture(match_info_array, 0);
2566 end = RegExpImpl::GetCapture(match_info_array, 1);
2567 }
2568
2569 int length = subject->length();
2570 int new_length = length - (end - start);
2571 if (new_length == 0) {
2572 return Heap::empty_string();
2573 }
2574 Handle<ResultSeqString> answer;
2575 if (ResultSeqString::kHasAsciiEncoding) {
2576 answer =
2577 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2578 } else {
2579 answer =
2580 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2581 }
2582
2583 // If the regexp isn't global, only match once.
2584 if (!regexp_handle->GetFlags().is_global()) {
2585 if (start > 0) {
2586 String::WriteToFlat(*subject_handle,
2587 answer->GetChars(),
2588 0,
2589 start);
2590 }
2591 if (end < length) {
2592 String::WriteToFlat(*subject_handle,
2593 answer->GetChars() + start,
2594 end,
2595 length);
2596 }
2597 return *answer;
2598 }
2599
2600 int prev = 0; // Index of end of last match.
2601 int next = 0; // Start of next search (prev unless last match was empty).
2602 int position = 0;
2603
2604 do {
2605 if (prev < start) {
2606 // Add substring subject[prev;start] to answer string.
2607 String::WriteToFlat(*subject_handle,
2608 answer->GetChars() + position,
2609 prev,
2610 start);
2611 position += start - prev;
2612 }
2613 prev = end;
2614 next = end;
2615 // Continue from where the match ended, unless it was an empty match.
2616 if (start == end) {
2617 next++;
2618 if (next > length) break;
2619 }
2620 match = RegExpImpl::Exec(regexp_handle,
2621 subject_handle,
2622 next,
2623 last_match_info_handle);
2624 if (match.is_null()) return Failure::Exception();
2625 if (match->IsNull()) break;
2626
2627 ASSERT(last_match_info_handle->HasFastElements());
2628 HandleScope loop_scope;
2629 {
2630 AssertNoAllocation match_info_array_is_not_in_a_handle;
2631 FixedArray* match_info_array =
2632 FixedArray::cast(last_match_info_handle->elements());
2633 start = RegExpImpl::GetCapture(match_info_array, 0);
2634 end = RegExpImpl::GetCapture(match_info_array, 1);
2635 }
2636 } while (true);
2637
2638 if (prev < length) {
2639 // Add substring subject[prev;length] to answer string.
2640 String::WriteToFlat(*subject_handle,
2641 answer->GetChars() + position,
2642 prev,
2643 length);
2644 position += length - prev;
2645 }
2646
2647 if (position == 0) {
2648 return Heap::empty_string();
2649 }
2650
2651 // Shorten string and fill
2652 int string_size = ResultSeqString::SizeFor(position);
2653 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2654 int delta = allocated_string_size - string_size;
2655
2656 answer->set_length(position);
2657 if (delta == 0) return *answer;
2658
2659 Address end_of_string = answer->address() + string_size;
2660 Heap::CreateFillerObjectAt(end_of_string, delta);
2661
2662 return *answer;
2663}
2664
2665
lrn@chromium.org303ada72010-10-27 09:33:13 +00002666static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002667 ASSERT(args.length() == 4);
2668
2669 CONVERT_CHECKED(String, subject, args[0]);
2670 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002671 Object* flat_subject;
2672 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2673 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2674 return maybe_flat_subject;
2675 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002676 }
2677 subject = String::cast(flat_subject);
2678 }
2679
2680 CONVERT_CHECKED(String, replacement, args[2]);
2681 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002682 Object* flat_replacement;
2683 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2684 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2685 return maybe_flat_replacement;
2686 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002687 }
2688 replacement = String::cast(flat_replacement);
2689 }
2690
2691 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2692 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2693
2694 ASSERT(last_match_info->HasFastElements());
2695
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002696 if (replacement->length() == 0) {
2697 if (subject->HasOnlyAsciiChars()) {
2698 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2699 subject, regexp, last_match_info);
2700 } else {
2701 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2702 subject, regexp, last_match_info);
2703 }
2704 }
2705
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002706 return StringReplaceRegExpWithString(subject,
2707 regexp,
2708 replacement,
2709 last_match_info);
2710}
2711
2712
ager@chromium.org7c537e22008-10-16 08:43:32 +00002713// Perform string match of pattern on subject, starting at start index.
2714// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002715// and should check that pat->length() + start_index <= sub->length().
ager@chromium.org7c537e22008-10-16 08:43:32 +00002716int Runtime::StringMatch(Handle<String> sub,
2717 Handle<String> pat,
2718 int start_index) {
2719 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002720 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002721
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002722 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002723 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002724
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002725 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002726 if (start_index + pattern_length > subject_length) return -1;
2727
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002728 if (!sub->IsFlat()) FlattenString(sub);
2729 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002730
ager@chromium.org7c537e22008-10-16 08:43:32 +00002731 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002732 // Extract flattened substrings of cons strings before determining asciiness.
2733 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002734 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002735 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002736 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002737
ager@chromium.org7c537e22008-10-16 08:43:32 +00002738 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002739 if (seq_pat->IsAsciiRepresentation()) {
2740 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2741 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002742 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002743 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002744 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002745 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002746 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2747 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002748 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002749 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002750 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002751}
2752
2753
lrn@chromium.org303ada72010-10-27 09:33:13 +00002754static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002755 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002756 ASSERT(args.length() == 3);
2757
ager@chromium.org7c537e22008-10-16 08:43:32 +00002758 CONVERT_ARG_CHECKED(String, sub, 0);
2759 CONVERT_ARG_CHECKED(String, pat, 1);
2760
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002761 Object* index = args[2];
2762 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002763 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002764
ager@chromium.org870a0b62008-11-04 11:43:05 +00002765 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002766 int position = Runtime::StringMatch(sub, pat, start_index);
2767 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002768}
2769
2770
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002771template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002772static int StringMatchBackwards(Vector<const schar> subject,
2773 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002774 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002775 int pattern_length = pattern.length();
2776 ASSERT(pattern_length >= 1);
2777 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002778
2779 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002780 for (int i = 0; i < pattern_length; i++) {
2781 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002782 if (c > String::kMaxAsciiCharCode) {
2783 return -1;
2784 }
2785 }
2786 }
2787
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002788 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002789 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002790 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002791 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002792 while (j < pattern_length) {
2793 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002794 break;
2795 }
2796 j++;
2797 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002798 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002799 return i;
2800 }
2801 }
2802 return -1;
2803}
2804
lrn@chromium.org303ada72010-10-27 09:33:13 +00002805static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002806 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002807 ASSERT(args.length() == 3);
2808
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002809 CONVERT_ARG_CHECKED(String, sub, 0);
2810 CONVERT_ARG_CHECKED(String, pat, 1);
2811
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002812 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002813 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002814 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002815
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002816 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002817 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002818
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002819 if (start_index + pat_length > sub_length) {
2820 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002821 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002822
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002823 if (pat_length == 0) {
2824 return Smi::FromInt(start_index);
2825 }
2826
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002827 if (!sub->IsFlat()) FlattenString(sub);
2828 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002829
2830 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2831
2832 int position = -1;
2833
2834 if (pat->IsAsciiRepresentation()) {
2835 Vector<const char> pat_vector = pat->ToAsciiVector();
2836 if (sub->IsAsciiRepresentation()) {
2837 position = StringMatchBackwards(sub->ToAsciiVector(),
2838 pat_vector,
2839 start_index);
2840 } else {
2841 position = StringMatchBackwards(sub->ToUC16Vector(),
2842 pat_vector,
2843 start_index);
2844 }
2845 } else {
2846 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2847 if (sub->IsAsciiRepresentation()) {
2848 position = StringMatchBackwards(sub->ToAsciiVector(),
2849 pat_vector,
2850 start_index);
2851 } else {
2852 position = StringMatchBackwards(sub->ToUC16Vector(),
2853 pat_vector,
2854 start_index);
2855 }
2856 }
2857
2858 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002859}
2860
2861
lrn@chromium.org303ada72010-10-27 09:33:13 +00002862static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002863 NoHandleAllocation ha;
2864 ASSERT(args.length() == 2);
2865
2866 CONVERT_CHECKED(String, str1, args[0]);
2867 CONVERT_CHECKED(String, str2, args[1]);
2868
2869 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002870 int str1_length = str1->length();
2871 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002872
2873 // Decide trivial cases without flattening.
2874 if (str1_length == 0) {
2875 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2876 return Smi::FromInt(-str2_length);
2877 } else {
2878 if (str2_length == 0) return Smi::FromInt(str1_length);
2879 }
2880
2881 int end = str1_length < str2_length ? str1_length : str2_length;
2882
2883 // No need to flatten if we are going to find the answer on the first
2884 // character. At this point we know there is at least one character
2885 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002886 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002887 if (d != 0) return Smi::FromInt(d);
2888
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002889 str1->TryFlatten();
2890 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002891
2892 static StringInputBuffer buf1;
2893 static StringInputBuffer buf2;
2894
2895 buf1.Reset(str1);
2896 buf2.Reset(str2);
2897
2898 for (int i = 0; i < end; i++) {
2899 uint16_t char1 = buf1.GetNext();
2900 uint16_t char2 = buf2.GetNext();
2901 if (char1 != char2) return Smi::FromInt(char1 - char2);
2902 }
2903
2904 return Smi::FromInt(str1_length - str2_length);
2905}
2906
2907
lrn@chromium.org303ada72010-10-27 09:33:13 +00002908static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002909 NoHandleAllocation ha;
2910 ASSERT(args.length() == 3);
2911
2912 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002913 Object* from = args[1];
2914 Object* to = args[2];
2915 int start, end;
2916 // We have a fast integer-only case here to avoid a conversion to double in
2917 // the common case where from and to are Smis.
2918 if (from->IsSmi() && to->IsSmi()) {
2919 start = Smi::cast(from)->value();
2920 end = Smi::cast(to)->value();
2921 } else {
2922 CONVERT_DOUBLE_CHECKED(from_number, from);
2923 CONVERT_DOUBLE_CHECKED(to_number, to);
2924 start = FastD2I(from_number);
2925 end = FastD2I(to_number);
2926 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002927 RUNTIME_ASSERT(end >= start);
2928 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002929 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002930 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002931 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002932}
2933
2934
lrn@chromium.org303ada72010-10-27 09:33:13 +00002935static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002936 ASSERT_EQ(3, args.length());
2937
2938 CONVERT_ARG_CHECKED(String, subject, 0);
2939 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2940 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2941 HandleScope handles;
2942
2943 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2944
2945 if (match.is_null()) {
2946 return Failure::Exception();
2947 }
2948 if (match->IsNull()) {
2949 return Heap::null_value();
2950 }
2951 int length = subject->length();
2952
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002953 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002954 ZoneList<int> offsets(8);
2955 do {
2956 int start;
2957 int end;
2958 {
2959 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002960 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002961 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2962 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2963 }
2964 offsets.Add(start);
2965 offsets.Add(end);
2966 int index = start < end ? end : end + 1;
2967 if (index > length) break;
2968 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2969 if (match.is_null()) {
2970 return Failure::Exception();
2971 }
2972 } while (!match->IsNull());
2973 int matches = offsets.length() / 2;
2974 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2975 for (int i = 0; i < matches ; i++) {
2976 int from = offsets.at(i * 2);
2977 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002978 Handle<String> match = Factory::NewSubString(subject, from, to);
2979 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002980 }
2981 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2982 result->set_length(Smi::FromInt(matches));
2983 return *result;
2984}
2985
2986
lrn@chromium.org25156de2010-04-06 13:10:27 +00002987// Two smis before and after the match, for very long strings.
2988const int kMaxBuilderEntriesPerRegExpMatch = 5;
2989
2990
2991static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2992 Handle<JSArray> last_match_info,
2993 int match_start,
2994 int match_end) {
2995 // Fill last_match_info with a single capture.
2996 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2997 AssertNoAllocation no_gc;
2998 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2999 RegExpImpl::SetLastCaptureCount(elements, 2);
3000 RegExpImpl::SetLastInput(elements, *subject);
3001 RegExpImpl::SetLastSubject(elements, *subject);
3002 RegExpImpl::SetCapture(elements, 0, match_start);
3003 RegExpImpl::SetCapture(elements, 1, match_end);
3004}
3005
3006
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003007template <typename SubjectChar, typename PatternChar>
3008static bool SearchStringMultiple(Vector<const SubjectChar> subject,
3009 Vector<const PatternChar> pattern,
3010 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003011 FixedArrayBuilder* builder,
3012 int* match_pos) {
3013 int pos = *match_pos;
3014 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003015 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003016 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003017 StringSearch<PatternChar, SubjectChar> search(pattern);
3018 while (pos <= max_search_start) {
3019 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3020 *match_pos = pos;
3021 return false;
3022 }
3023 // Position of end of previous match.
3024 int match_end = pos + pattern_length;
3025 int new_pos = search.Search(subject, match_end);
3026 if (new_pos >= 0) {
3027 // A match.
3028 if (new_pos > match_end) {
3029 ReplacementStringBuilder::AddSubjectSlice(builder,
3030 match_end,
3031 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003032 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003033 pos = new_pos;
3034 builder->Add(pattern_string);
3035 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003036 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003037 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003038 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003039
lrn@chromium.org25156de2010-04-06 13:10:27 +00003040 if (pos < max_search_start) {
3041 ReplacementStringBuilder::AddSubjectSlice(builder,
3042 pos + pattern_length,
3043 subject_length);
3044 }
3045 *match_pos = pos;
3046 return true;
3047}
3048
3049
3050static bool SearchStringMultiple(Handle<String> subject,
3051 Handle<String> pattern,
3052 Handle<JSArray> last_match_info,
3053 FixedArrayBuilder* builder) {
3054 ASSERT(subject->IsFlat());
3055 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003056
3057 // Treating as if a previous match was before first character.
3058 int match_pos = -pattern->length();
3059
3060 for (;;) { // Break when search complete.
3061 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3062 AssertNoAllocation no_gc;
3063 if (subject->IsAsciiRepresentation()) {
3064 Vector<const char> subject_vector = subject->ToAsciiVector();
3065 if (pattern->IsAsciiRepresentation()) {
3066 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003067 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003068 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003069 builder,
3070 &match_pos)) break;
3071 } else {
3072 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003073 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003074 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003075 builder,
3076 &match_pos)) break;
3077 }
3078 } else {
3079 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3080 if (pattern->IsAsciiRepresentation()) {
3081 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003082 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003083 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003084 builder,
3085 &match_pos)) break;
3086 } else {
3087 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003088 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003089 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003090 builder,
3091 &match_pos)) break;
3092 }
3093 }
3094 }
3095
3096 if (match_pos >= 0) {
3097 SetLastMatchInfoNoCaptures(subject,
3098 last_match_info,
3099 match_pos,
3100 match_pos + pattern->length());
3101 return true;
3102 }
3103 return false; // No matches at all.
3104}
3105
3106
3107static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3108 Handle<String> subject,
3109 Handle<JSRegExp> regexp,
3110 Handle<JSArray> last_match_array,
3111 FixedArrayBuilder* builder) {
3112 ASSERT(subject->IsFlat());
3113 int match_start = -1;
3114 int match_end = 0;
3115 int pos = 0;
3116 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3117 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3118
3119 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003120 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003121 int subject_length = subject->length();
3122
3123 for (;;) { // Break on failure, return on exception.
3124 RegExpImpl::IrregexpResult result =
3125 RegExpImpl::IrregexpExecOnce(regexp,
3126 subject,
3127 pos,
3128 register_vector);
3129 if (result == RegExpImpl::RE_SUCCESS) {
3130 match_start = register_vector[0];
3131 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3132 if (match_end < match_start) {
3133 ReplacementStringBuilder::AddSubjectSlice(builder,
3134 match_end,
3135 match_start);
3136 }
3137 match_end = register_vector[1];
3138 HandleScope loop_scope;
3139 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3140 if (match_start != match_end) {
3141 pos = match_end;
3142 } else {
3143 pos = match_end + 1;
3144 if (pos > subject_length) break;
3145 }
3146 } else if (result == RegExpImpl::RE_FAILURE) {
3147 break;
3148 } else {
3149 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3150 return result;
3151 }
3152 }
3153
3154 if (match_start >= 0) {
3155 if (match_end < subject_length) {
3156 ReplacementStringBuilder::AddSubjectSlice(builder,
3157 match_end,
3158 subject_length);
3159 }
3160 SetLastMatchInfoNoCaptures(subject,
3161 last_match_array,
3162 match_start,
3163 match_end);
3164 return RegExpImpl::RE_SUCCESS;
3165 } else {
3166 return RegExpImpl::RE_FAILURE; // No matches at all.
3167 }
3168}
3169
3170
3171static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3172 Handle<String> subject,
3173 Handle<JSRegExp> regexp,
3174 Handle<JSArray> last_match_array,
3175 FixedArrayBuilder* builder) {
3176
3177 ASSERT(subject->IsFlat());
3178 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3179 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3180
3181 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003182 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003183
3184 RegExpImpl::IrregexpResult result =
3185 RegExpImpl::IrregexpExecOnce(regexp,
3186 subject,
3187 0,
3188 register_vector);
3189
3190 int capture_count = regexp->CaptureCount();
3191 int subject_length = subject->length();
3192
3193 // Position to search from.
3194 int pos = 0;
3195 // End of previous match. Differs from pos if match was empty.
3196 int match_end = 0;
3197 if (result == RegExpImpl::RE_SUCCESS) {
3198 // Need to keep a copy of the previous match for creating last_match_info
3199 // at the end, so we have two vectors that we swap between.
3200 OffsetsVector registers2(required_registers);
3201 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3202
3203 do {
3204 int match_start = register_vector[0];
3205 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3206 if (match_end < match_start) {
3207 ReplacementStringBuilder::AddSubjectSlice(builder,
3208 match_end,
3209 match_start);
3210 }
3211 match_end = register_vector[1];
3212
3213 {
3214 // Avoid accumulating new handles inside loop.
3215 HandleScope temp_scope;
3216 // Arguments array to replace function is match, captures, index and
3217 // subject, i.e., 3 + capture count in total.
3218 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003219 Handle<String> match = Factory::NewSubString(subject,
3220 match_start,
3221 match_end);
3222 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003223 for (int i = 1; i <= capture_count; i++) {
3224 int start = register_vector[i * 2];
3225 if (start >= 0) {
3226 int end = register_vector[i * 2 + 1];
3227 ASSERT(start <= end);
3228 Handle<String> substring = Factory::NewSubString(subject,
3229 start,
3230 end);
3231 elements->set(i, *substring);
3232 } else {
3233 ASSERT(register_vector[i * 2 + 1] < 0);
3234 elements->set(i, Heap::undefined_value());
3235 }
3236 }
3237 elements->set(capture_count + 1, Smi::FromInt(match_start));
3238 elements->set(capture_count + 2, *subject);
3239 builder->Add(*Factory::NewJSArrayWithElements(elements));
3240 }
3241 // Swap register vectors, so the last successful match is in
3242 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003243 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003244 prev_register_vector = register_vector;
3245 register_vector = tmp;
3246
3247 if (match_end > match_start) {
3248 pos = match_end;
3249 } else {
3250 pos = match_end + 1;
3251 if (pos > subject_length) {
3252 break;
3253 }
3254 }
3255
3256 result = RegExpImpl::IrregexpExecOnce(regexp,
3257 subject,
3258 pos,
3259 register_vector);
3260 } while (result == RegExpImpl::RE_SUCCESS);
3261
3262 if (result != RegExpImpl::RE_EXCEPTION) {
3263 // Finished matching, with at least one match.
3264 if (match_end < subject_length) {
3265 ReplacementStringBuilder::AddSubjectSlice(builder,
3266 match_end,
3267 subject_length);
3268 }
3269
3270 int last_match_capture_count = (capture_count + 1) * 2;
3271 int last_match_array_size =
3272 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3273 last_match_array->EnsureSize(last_match_array_size);
3274 AssertNoAllocation no_gc;
3275 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3276 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3277 RegExpImpl::SetLastSubject(elements, *subject);
3278 RegExpImpl::SetLastInput(elements, *subject);
3279 for (int i = 0; i < last_match_capture_count; i++) {
3280 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3281 }
3282 return RegExpImpl::RE_SUCCESS;
3283 }
3284 }
3285 // No matches at all, return failure or exception result directly.
3286 return result;
3287}
3288
3289
lrn@chromium.org303ada72010-10-27 09:33:13 +00003290static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003291 ASSERT(args.length() == 4);
3292 HandleScope handles;
3293
3294 CONVERT_ARG_CHECKED(String, subject, 1);
3295 if (!subject->IsFlat()) { FlattenString(subject); }
3296 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3297 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3298 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3299
3300 ASSERT(last_match_info->HasFastElements());
3301 ASSERT(regexp->GetFlags().is_global());
3302 Handle<FixedArray> result_elements;
3303 if (result_array->HasFastElements()) {
3304 result_elements =
3305 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3306 } else {
3307 result_elements = Factory::NewFixedArrayWithHoles(16);
3308 }
3309 FixedArrayBuilder builder(result_elements);
3310
3311 if (regexp->TypeTag() == JSRegExp::ATOM) {
3312 Handle<String> pattern(
3313 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003314 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003315 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3316 return *builder.ToJSArray(result_array);
3317 }
3318 return Heap::null_value();
3319 }
3320
3321 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3322
3323 RegExpImpl::IrregexpResult result;
3324 if (regexp->CaptureCount() == 0) {
3325 result = SearchRegExpNoCaptureMultiple(subject,
3326 regexp,
3327 last_match_info,
3328 &builder);
3329 } else {
3330 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3331 }
3332 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3333 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3334 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3335 return Failure::Exception();
3336}
3337
3338
lrn@chromium.org303ada72010-10-27 09:33:13 +00003339static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003340 NoHandleAllocation ha;
3341 ASSERT(args.length() == 2);
3342
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003343 // Fast case where the result is a one character string.
3344 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3345 int value = Smi::cast(args[0])->value();
3346 int radix = Smi::cast(args[1])->value();
3347 if (value >= 0 && value < radix) {
3348 RUNTIME_ASSERT(radix <= 36);
3349 // Character array used for conversion.
3350 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3351 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3352 }
3353 }
3354
3355 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003356 CONVERT_DOUBLE_CHECKED(value, args[0]);
3357 if (isnan(value)) {
3358 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3359 }
3360 if (isinf(value)) {
3361 if (value < 0) {
3362 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3363 }
3364 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3365 }
3366 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3367 int radix = FastD2I(radix_number);
3368 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3369 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003370 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003371 DeleteArray(str);
3372 return result;
3373}
3374
3375
lrn@chromium.org303ada72010-10-27 09:33:13 +00003376static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003377 NoHandleAllocation ha;
3378 ASSERT(args.length() == 2);
3379
3380 CONVERT_DOUBLE_CHECKED(value, args[0]);
3381 if (isnan(value)) {
3382 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3383 }
3384 if (isinf(value)) {
3385 if (value < 0) {
3386 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3387 }
3388 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3389 }
3390 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3391 int f = FastD2I(f_number);
3392 RUNTIME_ASSERT(f >= 0);
3393 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003394 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003395 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003396 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003397}
3398
3399
lrn@chromium.org303ada72010-10-27 09:33:13 +00003400static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401 NoHandleAllocation ha;
3402 ASSERT(args.length() == 2);
3403
3404 CONVERT_DOUBLE_CHECKED(value, args[0]);
3405 if (isnan(value)) {
3406 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3407 }
3408 if (isinf(value)) {
3409 if (value < 0) {
3410 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3411 }
3412 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3413 }
3414 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3415 int f = FastD2I(f_number);
3416 RUNTIME_ASSERT(f >= -1 && f <= 20);
3417 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003418 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003419 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003420 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003421}
3422
3423
lrn@chromium.org303ada72010-10-27 09:33:13 +00003424static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003425 NoHandleAllocation ha;
3426 ASSERT(args.length() == 2);
3427
3428 CONVERT_DOUBLE_CHECKED(value, args[0]);
3429 if (isnan(value)) {
3430 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3431 }
3432 if (isinf(value)) {
3433 if (value < 0) {
3434 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3435 }
3436 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3437 }
3438 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3439 int f = FastD2I(f_number);
3440 RUNTIME_ASSERT(f >= 1 && f <= 21);
3441 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003442 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003443 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003444 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003445}
3446
3447
3448// Returns a single character string where first character equals
3449// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003450static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003451 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003452 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003453 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003454 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003455 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003456 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457}
3458
3459
lrn@chromium.org303ada72010-10-27 09:33:13 +00003460MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3461 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003462 // Handle [] indexing on Strings
3463 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003464 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3465 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466 }
3467
3468 // Handle [] indexing on String objects
3469 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003470 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3471 Handle<Object> result =
3472 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3473 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003474 }
3475
3476 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003477 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003478 return prototype->GetElement(index);
3479 }
3480
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003481 return GetElement(object, index);
3482}
3483
3484
lrn@chromium.org303ada72010-10-27 09:33:13 +00003485MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003486 return object->GetElement(index);
3487}
3488
3489
lrn@chromium.org303ada72010-10-27 09:33:13 +00003490MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3491 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003492 HandleScope scope;
3493
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003494 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003495 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003496 Handle<Object> error =
3497 Factory::NewTypeError("non_object_property_load",
3498 HandleVector(args, 2));
3499 return Top::Throw(*error);
3500 }
3501
3502 // Check if the given key is an array index.
3503 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003504 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003505 return GetElementOrCharAt(object, index);
3506 }
3507
3508 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003509 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003510 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003511 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003512 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513 bool has_pending_exception = false;
3514 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003515 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003516 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003517 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003518 }
3519
ager@chromium.org32912102009-01-16 10:38:43 +00003520 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003521 // the element if so.
3522 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003523 return GetElementOrCharAt(object, index);
3524 } else {
3525 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003526 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003527 }
3528}
3529
3530
lrn@chromium.org303ada72010-10-27 09:33:13 +00003531static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003532 NoHandleAllocation ha;
3533 ASSERT(args.length() == 2);
3534
3535 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003536 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003537
3538 return Runtime::GetObjectProperty(object, key);
3539}
3540
3541
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003542// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003543static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003544 NoHandleAllocation ha;
3545 ASSERT(args.length() == 2);
3546
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003547 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003548 // itself.
3549 //
3550 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003551 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003552 // global proxy object never has properties. This is the case
3553 // because the global proxy object forwards everything to its hidden
3554 // prototype including local lookups.
3555 //
3556 // Additionally, we need to make sure that we do not cache results
3557 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003558 if (args[0]->IsJSObject() &&
3559 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003560 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003561 args[1]->IsString()) {
3562 JSObject* receiver = JSObject::cast(args[0]);
3563 String* key = String::cast(args[1]);
3564 if (receiver->HasFastProperties()) {
3565 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003566 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003567 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3568 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003569 Object* value = receiver->FastPropertyAt(offset);
3570 return value->IsTheHole() ? Heap::undefined_value() : value;
3571 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003572 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003573 LookupResult result;
3574 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003575 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003576 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003577 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003578 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003579 }
3580 } else {
3581 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003582 StringDictionary* dictionary = receiver->property_dictionary();
3583 int entry = dictionary->FindEntry(key);
3584 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003585 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003586 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003587 if (!receiver->IsGlobalObject()) return value;
3588 value = JSGlobalPropertyCell::cast(value)->value();
3589 if (!value->IsTheHole()) return value;
3590 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003591 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003592 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003593 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3594 // Fast case for string indexing using [] with a smi index.
3595 HandleScope scope;
3596 Handle<String> str = args.at<String>(0);
3597 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003598 if (index >= 0 && index < str->length()) {
3599 Handle<Object> result = GetCharAt(str, index);
3600 return *result;
3601 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003602 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003603
3604 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003605 return Runtime::GetObjectProperty(args.at<Object>(0),
3606 args.at<Object>(1));
3607}
3608
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003609// Implements part of 8.12.9 DefineOwnProperty.
3610// There are 3 cases that lead here:
3611// Step 4b - define a new accessor property.
3612// Steps 9c & 12 - replace an existing data property with an accessor property.
3613// Step 12 - update an existing accessor property with an accessor or generic
3614// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003615static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003616 ASSERT(args.length() == 5);
3617 HandleScope scope;
3618 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3619 CONVERT_CHECKED(String, name, args[1]);
3620 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003621 Object* fun = args[3];
3622 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003623 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3624 int unchecked = flag_attr->value();
3625 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3626 RUNTIME_ASSERT(!obj->IsNull());
3627 LookupResult result;
3628 obj->LocalLookupRealNamedProperty(name, &result);
3629
3630 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3631 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3632 // delete it to avoid running into trouble in DefineAccessor, which
3633 // handles this incorrectly if the property is readonly (does nothing)
3634 if (result.IsProperty() &&
3635 (result.type() == FIELD || result.type() == NORMAL
3636 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003637 Object* ok;
3638 { MaybeObject* maybe_ok =
3639 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3640 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3641 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003642 }
3643 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3644}
3645
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003646// Implements part of 8.12.9 DefineOwnProperty.
3647// There are 3 cases that lead here:
3648// Step 4a - define a new data property.
3649// Steps 9b & 12 - replace an existing accessor property with a data property.
3650// Step 12 - update an existing data property with a data or generic
3651// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003652static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003653 ASSERT(args.length() == 4);
3654 HandleScope scope;
3655 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3656 CONVERT_ARG_CHECKED(String, name, 1);
3657 Handle<Object> obj_value = args.at<Object>(2);
3658
3659 CONVERT_CHECKED(Smi, flag, args[3]);
3660 int unchecked = flag->value();
3661 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3662
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003663 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3664
3665 // Check if this is an element.
3666 uint32_t index;
3667 bool is_element = name->AsArrayIndex(&index);
3668
3669 // Special case for elements if any of the flags are true.
3670 // If elements are in fast case we always implicitly assume that:
3671 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3672 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3673 is_element) {
3674 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003675 if (js_object->IsJSGlobalProxy()) {
3676 Handle<Object> proto(js_object->GetPrototype());
3677 // If proxy is detached, ignore the assignment. Alternatively,
3678 // we could throw an exception.
3679 if (proto->IsNull()) return *obj_value;
3680 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003681 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003682 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003683 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003684 // Make sure that we never go back to fast case.
3685 dictionary->set_requires_slow_elements();
3686 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003687 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003688 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003689 }
3690
ager@chromium.org5c838252010-02-19 08:53:10 +00003691 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003692 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003693
ager@chromium.org5c838252010-02-19 08:53:10 +00003694 // Take special care when attributes are different and there is already
3695 // a property. For simplicity we normalize the property which enables us
3696 // to not worry about changing the instance_descriptor and creating a new
3697 // map. The current version of SetObjectProperty does not handle attributes
3698 // correctly in the case where a property is a field and is reset with
3699 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003700 if (result.IsProperty() &&
3701 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003702 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003703 if (js_object->IsJSGlobalProxy()) {
3704 // Since the result is a property, the prototype will exist so
3705 // we don't have to check for null.
3706 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003707 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003708 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003709 // Use IgnoreAttributes version since a readonly property may be
3710 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003711 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3712 *obj_value,
3713 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003714 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003715
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003716 return Runtime::ForceSetObjectProperty(js_object, name, obj_value, attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003717}
3718
3719
lrn@chromium.org303ada72010-10-27 09:33:13 +00003720MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3721 Handle<Object> key,
3722 Handle<Object> value,
3723 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003724 HandleScope scope;
3725
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003726 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003727 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003728 Handle<Object> error =
3729 Factory::NewTypeError("non_object_property_store",
3730 HandleVector(args, 2));
3731 return Top::Throw(*error);
3732 }
3733
3734 // If the object isn't a JavaScript object, we ignore the store.
3735 if (!object->IsJSObject()) return *value;
3736
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003737 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3738
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003739 // Check if the given key is an array index.
3740 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003741 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003742 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3743 // of a string using [] notation. We need to support this too in
3744 // JavaScript.
3745 // In the case of a String object we just need to redirect the assignment to
3746 // the underlying string if the index is in range. Since the underlying
3747 // string does nothing with the assignment then we can ignore such
3748 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003749 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003750 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003751 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003752
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003753 Handle<Object> result = SetElement(js_object, index, value);
3754 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003755 return *value;
3756 }
3757
3758 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003759 Handle<Object> result;
3760 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003761 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003762 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003763 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003764 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003765 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003766 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003767 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003768 return *value;
3769 }
3770
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003771 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003772 bool has_pending_exception = false;
3773 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3774 if (has_pending_exception) return Failure::Exception();
3775 Handle<String> name = Handle<String>::cast(converted);
3776
3777 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003778 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003779 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003780 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003781 }
3782}
3783
3784
lrn@chromium.org303ada72010-10-27 09:33:13 +00003785MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3786 Handle<Object> key,
3787 Handle<Object> value,
3788 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003789 HandleScope scope;
3790
3791 // Check if the given key is an array index.
3792 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003793 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003794 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3795 // of a string using [] notation. We need to support this too in
3796 // JavaScript.
3797 // In the case of a String object we just need to redirect the assignment to
3798 // the underlying string if the index is in range. Since the underlying
3799 // string does nothing with the assignment then we can ignore such
3800 // assignments.
3801 if (js_object->IsStringObjectWithCharacterAt(index)) {
3802 return *value;
3803 }
3804
3805 return js_object->SetElement(index, *value);
3806 }
3807
3808 if (key->IsString()) {
3809 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003810 return js_object->SetElement(index, *value);
3811 } else {
3812 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003813 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003814 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
3815 *value,
3816 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003817 }
3818 }
3819
3820 // Call-back into JavaScript to convert the key to a string.
3821 bool has_pending_exception = false;
3822 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3823 if (has_pending_exception) return Failure::Exception();
3824 Handle<String> name = Handle<String>::cast(converted);
3825
3826 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003827 return js_object->SetElement(index, *value);
3828 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003829 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003830 }
3831}
3832
3833
lrn@chromium.org303ada72010-10-27 09:33:13 +00003834MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3835 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003836 HandleScope scope;
3837
3838 // Check if the given key is an array index.
3839 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003840 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003841 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3842 // characters of a string using [] notation. In the case of a
3843 // String object we just need to redirect the deletion to the
3844 // underlying string if the index is in range. Since the
3845 // underlying string does nothing with the deletion, we can ignore
3846 // such deletions.
3847 if (js_object->IsStringObjectWithCharacterAt(index)) {
3848 return Heap::true_value();
3849 }
3850
3851 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3852 }
3853
3854 Handle<String> key_string;
3855 if (key->IsString()) {
3856 key_string = Handle<String>::cast(key);
3857 } else {
3858 // Call-back into JavaScript to convert the key to a string.
3859 bool has_pending_exception = false;
3860 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3861 if (has_pending_exception) return Failure::Exception();
3862 key_string = Handle<String>::cast(converted);
3863 }
3864
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003865 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003866 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3867}
3868
3869
lrn@chromium.org303ada72010-10-27 09:33:13 +00003870static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003871 NoHandleAllocation ha;
3872 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3873
3874 Handle<Object> object = args.at<Object>(0);
3875 Handle<Object> key = args.at<Object>(1);
3876 Handle<Object> value = args.at<Object>(2);
3877
3878 // Compute attributes.
3879 PropertyAttributes attributes = NONE;
3880 if (args.length() == 4) {
3881 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003882 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003883 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003884 RUNTIME_ASSERT(
3885 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3886 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003887 }
3888 return Runtime::SetObjectProperty(object, key, value, attributes);
3889}
3890
3891
3892// Set a local property, even if it is READ_ONLY. If the property does not
3893// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003894static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003895 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003896 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003897 CONVERT_CHECKED(JSObject, object, args[0]);
3898 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003899 // Compute attributes.
3900 PropertyAttributes attributes = NONE;
3901 if (args.length() == 4) {
3902 CONVERT_CHECKED(Smi, value_obj, args[3]);
3903 int unchecked_value = value_obj->value();
3904 // Only attribute bits should be set.
3905 RUNTIME_ASSERT(
3906 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3907 attributes = static_cast<PropertyAttributes>(unchecked_value);
3908 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003909
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003910 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003911 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003912}
3913
3914
lrn@chromium.org303ada72010-10-27 09:33:13 +00003915static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003916 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003917 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003918
3919 CONVERT_CHECKED(JSObject, object, args[0]);
3920 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003921 CONVERT_SMI_CHECKED(strict, args[2]);
3922 return object->DeleteProperty(key, strict == kStrictMode
3923 ? JSObject::STRICT_DELETION
3924 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003925}
3926
3927
ager@chromium.org9085a012009-05-11 19:22:57 +00003928static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3929 Handle<String> key) {
3930 if (object->HasLocalProperty(*key)) return Heap::true_value();
3931 // Handle hidden prototypes. If there's a hidden prototype above this thing
3932 // then we have to check it for properties, because they are supposed to
3933 // look like they are on this object.
3934 Handle<Object> proto(object->GetPrototype());
3935 if (proto->IsJSObject() &&
3936 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3937 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3938 }
3939 return Heap::false_value();
3940}
3941
3942
lrn@chromium.org303ada72010-10-27 09:33:13 +00003943static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003944 NoHandleAllocation ha;
3945 ASSERT(args.length() == 2);
3946 CONVERT_CHECKED(String, key, args[1]);
3947
ager@chromium.org9085a012009-05-11 19:22:57 +00003948 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003949 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003950 if (obj->IsJSObject()) {
3951 JSObject* object = JSObject::cast(obj);
3952 // Fast case - no interceptors.
3953 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3954 // Slow case. Either it's not there or we have an interceptor. We should
3955 // have handles for this kind of deal.
3956 HandleScope scope;
3957 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3958 Handle<String>(key));
3959 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003960 // Well, there is one exception: Handle [] on strings.
3961 uint32_t index;
3962 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003963 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003964 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003965 return Heap::true_value();
3966 }
3967 }
3968 return Heap::false_value();
3969}
3970
3971
lrn@chromium.org303ada72010-10-27 09:33:13 +00003972static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003973 NoHandleAllocation na;
3974 ASSERT(args.length() == 2);
3975
3976 // Only JS objects can have properties.
3977 if (args[0]->IsJSObject()) {
3978 JSObject* object = JSObject::cast(args[0]);
3979 CONVERT_CHECKED(String, key, args[1]);
3980 if (object->HasProperty(key)) return Heap::true_value();
3981 }
3982 return Heap::false_value();
3983}
3984
3985
lrn@chromium.org303ada72010-10-27 09:33:13 +00003986static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987 NoHandleAllocation na;
3988 ASSERT(args.length() == 2);
3989
3990 // Only JS objects can have elements.
3991 if (args[0]->IsJSObject()) {
3992 JSObject* object = JSObject::cast(args[0]);
3993 CONVERT_CHECKED(Smi, index_obj, args[1]);
3994 uint32_t index = index_obj->value();
3995 if (object->HasElement(index)) return Heap::true_value();
3996 }
3997 return Heap::false_value();
3998}
3999
4000
lrn@chromium.org303ada72010-10-27 09:33:13 +00004001static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004002 NoHandleAllocation ha;
4003 ASSERT(args.length() == 2);
4004
4005 CONVERT_CHECKED(JSObject, object, args[0]);
4006 CONVERT_CHECKED(String, key, args[1]);
4007
4008 uint32_t index;
4009 if (key->AsArrayIndex(&index)) {
4010 return Heap::ToBoolean(object->HasElement(index));
4011 }
4012
ager@chromium.org870a0b62008-11-04 11:43:05 +00004013 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
4014 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004015}
4016
4017
lrn@chromium.org303ada72010-10-27 09:33:13 +00004018static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 HandleScope scope;
4020 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004021 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004022 return *GetKeysFor(object);
4023}
4024
4025
4026// Returns either a FixedArray as Runtime_GetPropertyNames,
4027// or, if the given object has an enum cache that contains
4028// all enumerable properties of the object and its prototypes
4029// have none, the map of the object. This is used to speed up
4030// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004031static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 ASSERT(args.length() == 1);
4033
4034 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4035
4036 if (raw_object->IsSimpleEnum()) return raw_object->map();
4037
4038 HandleScope scope;
4039 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004040 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4041 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004042
4043 // Test again, since cache may have been built by preceding call.
4044 if (object->IsSimpleEnum()) return object->map();
4045
4046 return *content;
4047}
4048
4049
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004050// Find the length of the prototype chain that is to to handled as one. If a
4051// prototype object is hidden it is to be viewed as part of the the object it
4052// is prototype for.
4053static int LocalPrototypeChainLength(JSObject* obj) {
4054 int count = 1;
4055 Object* proto = obj->GetPrototype();
4056 while (proto->IsJSObject() &&
4057 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4058 count++;
4059 proto = JSObject::cast(proto)->GetPrototype();
4060 }
4061 return count;
4062}
4063
4064
4065// Return the names of the local named properties.
4066// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004067static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004068 HandleScope scope;
4069 ASSERT(args.length() == 1);
4070 if (!args[0]->IsJSObject()) {
4071 return Heap::undefined_value();
4072 }
4073 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4074
4075 // Skip the global proxy as it has no properties and always delegates to the
4076 // real global object.
4077 if (obj->IsJSGlobalProxy()) {
4078 // Only collect names if access is permitted.
4079 if (obj->IsAccessCheckNeeded() &&
4080 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
4081 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4082 return *Factory::NewJSArray(0);
4083 }
4084 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4085 }
4086
4087 // Find the number of objects making up this.
4088 int length = LocalPrototypeChainLength(*obj);
4089
4090 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004091 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004092 int total_property_count = 0;
4093 Handle<JSObject> jsproto = obj;
4094 for (int i = 0; i < length; i++) {
4095 // Only collect names if access is permitted.
4096 if (jsproto->IsAccessCheckNeeded() &&
4097 !Top::MayNamedAccess(*jsproto,
4098 Heap::undefined_value(),
4099 v8::ACCESS_KEYS)) {
4100 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4101 return *Factory::NewJSArray(0);
4102 }
4103 int n;
4104 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4105 local_property_count[i] = n;
4106 total_property_count += n;
4107 if (i < length - 1) {
4108 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4109 }
4110 }
4111
4112 // Allocate an array with storage for all the property names.
4113 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
4114
4115 // Get the property names.
4116 jsproto = obj;
4117 int proto_with_hidden_properties = 0;
4118 for (int i = 0; i < length; i++) {
4119 jsproto->GetLocalPropertyNames(*names,
4120 i == 0 ? 0 : local_property_count[i - 1]);
4121 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4122 proto_with_hidden_properties++;
4123 }
4124 if (i < length - 1) {
4125 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4126 }
4127 }
4128
4129 // Filter out name of hidden propeties object.
4130 if (proto_with_hidden_properties > 0) {
4131 Handle<FixedArray> old_names = names;
4132 names = Factory::NewFixedArray(
4133 names->length() - proto_with_hidden_properties);
4134 int dest_pos = 0;
4135 for (int i = 0; i < total_property_count; i++) {
4136 Object* name = old_names->get(i);
4137 if (name == Heap::hidden_symbol()) {
4138 continue;
4139 }
4140 names->set(dest_pos++, name);
4141 }
4142 }
4143
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004144 return *Factory::NewJSArrayWithElements(names);
4145}
4146
4147
4148// Return the names of the local indexed properties.
4149// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004150static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004151 HandleScope scope;
4152 ASSERT(args.length() == 1);
4153 if (!args[0]->IsJSObject()) {
4154 return Heap::undefined_value();
4155 }
4156 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4157
4158 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4159 Handle<FixedArray> names = Factory::NewFixedArray(n);
4160 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4161 return *Factory::NewJSArrayWithElements(names);
4162}
4163
4164
4165// Return information on whether an object has a named or indexed interceptor.
4166// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004167static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004168 HandleScope scope;
4169 ASSERT(args.length() == 1);
4170 if (!args[0]->IsJSObject()) {
4171 return Smi::FromInt(0);
4172 }
4173 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4174
4175 int result = 0;
4176 if (obj->HasNamedInterceptor()) result |= 2;
4177 if (obj->HasIndexedInterceptor()) result |= 1;
4178
4179 return Smi::FromInt(result);
4180}
4181
4182
4183// Return property names from named interceptor.
4184// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004185static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004186 HandleScope scope;
4187 ASSERT(args.length() == 1);
4188 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4189
4190 if (obj->HasNamedInterceptor()) {
4191 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4192 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4193 }
4194 return Heap::undefined_value();
4195}
4196
4197
4198// Return element names from indexed interceptor.
4199// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004200static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004201 HandleScope scope;
4202 ASSERT(args.length() == 1);
4203 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4204
4205 if (obj->HasIndexedInterceptor()) {
4206 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4207 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4208 }
4209 return Heap::undefined_value();
4210}
4211
4212
lrn@chromium.org303ada72010-10-27 09:33:13 +00004213static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004214 ASSERT_EQ(args.length(), 1);
4215 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4216 HandleScope scope;
4217 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004218
4219 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004220 // Do access checks before going to the global object.
4221 if (object->IsAccessCheckNeeded() &&
4222 !Top::MayNamedAccess(*object, Heap::undefined_value(),
4223 v8::ACCESS_KEYS)) {
4224 Top::ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4225 return *Factory::NewJSArray(0);
4226 }
4227
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004228 Handle<Object> proto(object->GetPrototype());
4229 // If proxy is detached we simply return an empty array.
4230 if (proto->IsNull()) return *Factory::NewJSArray(0);
4231 object = Handle<JSObject>::cast(proto);
4232 }
4233
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004234 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4235 LOCAL_ONLY);
4236 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4237 // property array and since the result is mutable we have to create
4238 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004239 int length = contents->length();
4240 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4241 for (int i = 0; i < length; i++) {
4242 Object* entry = contents->get(i);
4243 if (entry->IsString()) {
4244 copy->set(i, entry);
4245 } else {
4246 ASSERT(entry->IsNumber());
4247 HandleScope scope;
4248 Handle<Object> entry_handle(entry);
4249 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4250 copy->set(i, *entry_str);
4251 }
4252 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004253 return *Factory::NewJSArrayWithElements(copy);
4254}
4255
4256
lrn@chromium.org303ada72010-10-27 09:33:13 +00004257static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004258 NoHandleAllocation ha;
4259 ASSERT(args.length() == 1);
4260
4261 // Compute the frame holding the arguments.
4262 JavaScriptFrameIterator it;
4263 it.AdvanceToArgumentsFrame();
4264 JavaScriptFrame* frame = it.frame();
4265
4266 // Get the actual number of provided arguments.
4267 const uint32_t n = frame->GetProvidedParametersCount();
4268
4269 // Try to convert the key to an index. If successful and within
4270 // index return the the argument from the frame.
4271 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004272 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004273 return frame->GetParameter(index);
4274 }
4275
4276 // Convert the key to a string.
4277 HandleScope scope;
4278 bool exception = false;
4279 Handle<Object> converted =
4280 Execution::ToString(args.at<Object>(0), &exception);
4281 if (exception) return Failure::Exception();
4282 Handle<String> key = Handle<String>::cast(converted);
4283
4284 // Try to convert the string key into an array index.
4285 if (key->AsArrayIndex(&index)) {
4286 if (index < n) {
4287 return frame->GetParameter(index);
4288 } else {
4289 return Top::initial_object_prototype()->GetElement(index);
4290 }
4291 }
4292
4293 // Handle special arguments properties.
4294 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4295 if (key->Equals(Heap::callee_symbol())) return frame->function();
4296
4297 // Lookup in the initial Object.prototype object.
4298 return Top::initial_object_prototype()->GetProperty(*key);
4299}
4300
4301
lrn@chromium.org303ada72010-10-27 09:33:13 +00004302static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004303 HandleScope scope;
4304
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004305 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004306 Handle<Object> object = args.at<Object>(0);
4307 if (object->IsJSObject()) {
4308 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004309 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004310 MaybeObject* ok = js_object->TransformToFastProperties(0);
4311 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004312 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004313 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004314 return *object;
4315}
4316
4317
lrn@chromium.org303ada72010-10-27 09:33:13 +00004318static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004319 HandleScope scope;
4320
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004321 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004322 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004323 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004324 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004325 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004326 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004327 return *object;
4328}
4329
4330
lrn@chromium.org303ada72010-10-27 09:33:13 +00004331static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004332 NoHandleAllocation ha;
4333 ASSERT(args.length() == 1);
4334
4335 return args[0]->ToBoolean();
4336}
4337
4338
4339// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4340// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004341static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004342 NoHandleAllocation ha;
4343
4344 Object* obj = args[0];
4345 if (obj->IsNumber()) return Heap::number_symbol();
4346 HeapObject* heap_obj = HeapObject::cast(obj);
4347
4348 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004349 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004350
4351 InstanceType instance_type = heap_obj->map()->instance_type();
4352 if (instance_type < FIRST_NONSTRING_TYPE) {
4353 return Heap::string_symbol();
4354 }
4355
4356 switch (instance_type) {
4357 case ODDBALL_TYPE:
4358 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4359 return Heap::boolean_symbol();
4360 }
4361 if (heap_obj->IsNull()) {
4362 return Heap::object_symbol();
4363 }
4364 ASSERT(heap_obj->IsUndefined());
4365 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004366 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004367 return Heap::function_symbol();
4368 default:
4369 // For any kind of object not handled above, the spec rule for
4370 // host objects gives that it is okay to return "object"
4371 return Heap::object_symbol();
4372 }
4373}
4374
4375
lrn@chromium.org25156de2010-04-06 13:10:27 +00004376static bool AreDigits(const char*s, int from, int to) {
4377 for (int i = from; i < to; i++) {
4378 if (s[i] < '0' || s[i] > '9') return false;
4379 }
4380
4381 return true;
4382}
4383
4384
4385static int ParseDecimalInteger(const char*s, int from, int to) {
4386 ASSERT(to - from < 10); // Overflow is not possible.
4387 ASSERT(from < to);
4388 int d = s[from] - '0';
4389
4390 for (int i = from + 1; i < to; i++) {
4391 d = 10 * d + (s[i] - '0');
4392 }
4393
4394 return d;
4395}
4396
4397
lrn@chromium.org303ada72010-10-27 09:33:13 +00004398static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004399 NoHandleAllocation ha;
4400 ASSERT(args.length() == 1);
4401 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004402 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004403
4404 // Fast case: short integer or some sorts of junk values.
4405 int len = subject->length();
4406 if (subject->IsSeqAsciiString()) {
4407 if (len == 0) return Smi::FromInt(0);
4408
4409 char const* data = SeqAsciiString::cast(subject)->GetChars();
4410 bool minus = (data[0] == '-');
4411 int start_pos = (minus ? 1 : 0);
4412
4413 if (start_pos == len) {
4414 return Heap::nan_value();
4415 } else if (data[start_pos] > '9') {
4416 // Fast check for a junk value. A valid string may start from a
4417 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4418 // the 'I' character ('Infinity'). All of that have codes not greater than
4419 // '9' except 'I'.
4420 if (data[start_pos] != 'I') {
4421 return Heap::nan_value();
4422 }
4423 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4424 // The maximal/minimal smi has 10 digits. If the string has less digits we
4425 // know it will fit into the smi-data type.
4426 int d = ParseDecimalInteger(data, start_pos, len);
4427 if (minus) {
4428 if (d == 0) return Heap::minus_zero_value();
4429 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004430 } else if (!subject->HasHashCode() &&
4431 len <= String::kMaxArrayIndexSize &&
4432 (len == 1 || data[0] != '0')) {
4433 // String hash is not calculated yet but all the data are present.
4434 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004435 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004436#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004437 subject->Hash(); // Force hash calculation.
4438 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4439 static_cast<int>(hash));
4440#endif
4441 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004442 }
4443 return Smi::FromInt(d);
4444 }
4445 }
4446
4447 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004448 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4449}
4450
4451
lrn@chromium.org303ada72010-10-27 09:33:13 +00004452static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004453 NoHandleAllocation ha;
4454 ASSERT(args.length() == 1);
4455
4456 CONVERT_CHECKED(JSArray, codes, args[0]);
4457 int length = Smi::cast(codes->length())->value();
4458
4459 // Check if the string can be ASCII.
4460 int i;
4461 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004462 Object* element;
4463 { MaybeObject* maybe_element = codes->GetElement(i);
4464 // We probably can't get an exception here, but just in order to enforce
4465 // the checking of inputs in the runtime calls we check here.
4466 if (!maybe_element->ToObject(&element)) return maybe_element;
4467 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004468 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4469 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4470 break;
4471 }
4472
lrn@chromium.org303ada72010-10-27 09:33:13 +00004473 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004474 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004475 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004476 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004477 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004478 }
4479
lrn@chromium.org303ada72010-10-27 09:33:13 +00004480 Object* object = NULL;
4481 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004482 String* result = String::cast(object);
4483 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004484 Object* element;
4485 { MaybeObject* maybe_element = codes->GetElement(i);
4486 if (!maybe_element->ToObject(&element)) return maybe_element;
4487 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004489 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490 }
4491 return result;
4492}
4493
4494
4495// kNotEscaped is generated by the following:
4496//
4497// #!/bin/perl
4498// for (my $i = 0; $i < 256; $i++) {
4499// print "\n" if $i % 16 == 0;
4500// my $c = chr($i);
4501// my $escaped = 1;
4502// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4503// print $escaped ? "0, " : "1, ";
4504// }
4505
4506
4507static bool IsNotEscaped(uint16_t character) {
4508 // Only for 8 bit characters, the rest are always escaped (in a different way)
4509 ASSERT(character < 256);
4510 static const char kNotEscaped[256] = {
4511 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4512 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4513 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4514 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4515 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4516 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4517 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4518 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4519 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4520 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4521 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4522 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4523 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4524 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4525 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4526 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4527 };
4528 return kNotEscaped[character] != 0;
4529}
4530
4531
lrn@chromium.org303ada72010-10-27 09:33:13 +00004532static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004533 const char hex_chars[] = "0123456789ABCDEF";
4534 NoHandleAllocation ha;
4535 ASSERT(args.length() == 1);
4536 CONVERT_CHECKED(String, source, args[0]);
4537
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004538 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004539
4540 int escaped_length = 0;
4541 int length = source->length();
4542 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004543 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004544 buffer->Reset(source);
4545 while (buffer->has_more()) {
4546 uint16_t character = buffer->GetNext();
4547 if (character >= 256) {
4548 escaped_length += 6;
4549 } else if (IsNotEscaped(character)) {
4550 escaped_length++;
4551 } else {
4552 escaped_length += 3;
4553 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004554 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004555 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004556 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004557 Top::context()->mark_out_of_memory();
4558 return Failure::OutOfMemoryException();
4559 }
4560 }
4561 }
4562 // No length change implies no change. Return original string if no change.
4563 if (escaped_length == length) {
4564 return source;
4565 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004566 Object* o;
4567 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4568 if (!maybe_o->ToObject(&o)) return maybe_o;
4569 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004570 String* destination = String::cast(o);
4571 int dest_position = 0;
4572
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004573 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004574 buffer->Rewind();
4575 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004576 uint16_t chr = buffer->GetNext();
4577 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004578 destination->Set(dest_position, '%');
4579 destination->Set(dest_position+1, 'u');
4580 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4581 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4582 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4583 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004584 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004585 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004586 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004587 dest_position++;
4588 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004589 destination->Set(dest_position, '%');
4590 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4591 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004592 dest_position += 3;
4593 }
4594 }
4595 return destination;
4596}
4597
4598
4599static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4600 static const signed char kHexValue['g'] = {
4601 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4602 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4603 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4604 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4605 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4606 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4607 -1, 10, 11, 12, 13, 14, 15 };
4608
4609 if (character1 > 'f') return -1;
4610 int hi = kHexValue[character1];
4611 if (hi == -1) return -1;
4612 if (character2 > 'f') return -1;
4613 int lo = kHexValue[character2];
4614 if (lo == -1) return -1;
4615 return (hi << 4) + lo;
4616}
4617
4618
ager@chromium.org870a0b62008-11-04 11:43:05 +00004619static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004620 int i,
4621 int length,
4622 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004623 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004624 int32_t hi = 0;
4625 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004626 if (character == '%' &&
4627 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004628 source->Get(i + 1) == 'u' &&
4629 (hi = TwoDigitHex(source->Get(i + 2),
4630 source->Get(i + 3))) != -1 &&
4631 (lo = TwoDigitHex(source->Get(i + 4),
4632 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004633 *step = 6;
4634 return (hi << 8) + lo;
4635 } else if (character == '%' &&
4636 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004637 (lo = TwoDigitHex(source->Get(i + 1),
4638 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004639 *step = 3;
4640 return lo;
4641 } else {
4642 *step = 1;
4643 return character;
4644 }
4645}
4646
4647
lrn@chromium.org303ada72010-10-27 09:33:13 +00004648static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004649 NoHandleAllocation ha;
4650 ASSERT(args.length() == 1);
4651 CONVERT_CHECKED(String, source, args[0]);
4652
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004653 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004654
4655 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004656 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004657
4658 int unescaped_length = 0;
4659 for (int i = 0; i < length; unescaped_length++) {
4660 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004661 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004662 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004663 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004664 i += step;
4665 }
4666
4667 // No length change implies no change. Return original string if no change.
4668 if (unescaped_length == length)
4669 return source;
4670
lrn@chromium.org303ada72010-10-27 09:33:13 +00004671 Object* o;
4672 { MaybeObject* maybe_o = ascii ?
4673 Heap::AllocateRawAsciiString(unescaped_length) :
4674 Heap::AllocateRawTwoByteString(unescaped_length);
4675 if (!maybe_o->ToObject(&o)) return maybe_o;
4676 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004677 String* destination = String::cast(o);
4678
4679 int dest_position = 0;
4680 for (int i = 0; i < length; dest_position++) {
4681 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004682 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004683 i += step;
4684 }
4685 return destination;
4686}
4687
4688
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004689static const unsigned int kQuoteTableLength = 128u;
4690
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004691static const int kJsonQuotesCharactersPerEntry = 8;
4692static const char* const JsonQuotes =
4693 "\\u0000 \\u0001 \\u0002 \\u0003 "
4694 "\\u0004 \\u0005 \\u0006 \\u0007 "
4695 "\\b \\t \\n \\u000b "
4696 "\\f \\r \\u000e \\u000f "
4697 "\\u0010 \\u0011 \\u0012 \\u0013 "
4698 "\\u0014 \\u0015 \\u0016 \\u0017 "
4699 "\\u0018 \\u0019 \\u001a \\u001b "
4700 "\\u001c \\u001d \\u001e \\u001f "
4701 " ! \\\" # "
4702 "$ % & ' "
4703 "( ) * + "
4704 ", - . / "
4705 "0 1 2 3 "
4706 "4 5 6 7 "
4707 "8 9 : ; "
4708 "< = > ? "
4709 "@ A B C "
4710 "D E F G "
4711 "H I J K "
4712 "L M N O "
4713 "P Q R S "
4714 "T U V W "
4715 "X Y Z [ "
4716 "\\\\ ] ^ _ "
4717 "` a b c "
4718 "d e f g "
4719 "h i j k "
4720 "l m n o "
4721 "p q r s "
4722 "t u v w "
4723 "x y z { "
4724 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004725
4726
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004727// For a string that is less than 32k characters it should always be
4728// possible to allocate it in new space.
4729static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4730
4731
4732// Doing JSON quoting cannot make the string more than this many times larger.
4733static const int kJsonQuoteWorstCaseBlowup = 6;
4734
4735
4736// Covers the entire ASCII range (all other characters are unchanged by JSON
4737// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004738static const byte JsonQuoteLengths[kQuoteTableLength] = {
4739 6, 6, 6, 6, 6, 6, 6, 6,
4740 2, 2, 2, 6, 2, 2, 6, 6,
4741 6, 6, 6, 6, 6, 6, 6, 6,
4742 6, 6, 6, 6, 6, 6, 6, 6,
4743 1, 1, 2, 1, 1, 1, 1, 1,
4744 1, 1, 1, 1, 1, 1, 1, 1,
4745 1, 1, 1, 1, 1, 1, 1, 1,
4746 1, 1, 1, 1, 1, 1, 1, 1,
4747 1, 1, 1, 1, 1, 1, 1, 1,
4748 1, 1, 1, 1, 1, 1, 1, 1,
4749 1, 1, 1, 1, 1, 1, 1, 1,
4750 1, 1, 1, 1, 2, 1, 1, 1,
4751 1, 1, 1, 1, 1, 1, 1, 1,
4752 1, 1, 1, 1, 1, 1, 1, 1,
4753 1, 1, 1, 1, 1, 1, 1, 1,
4754 1, 1, 1, 1, 1, 1, 1, 1,
4755};
4756
4757
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004758template <typename StringType>
4759MaybeObject* AllocateRawString(int length);
4760
4761
4762template <>
4763MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4764 return Heap::AllocateRawTwoByteString(length);
4765}
4766
4767
4768template <>
4769MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4770 return Heap::AllocateRawAsciiString(length);
4771}
4772
4773
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004774template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004775static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004776 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004777 const Char* read_cursor = characters.start();
4778 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004779 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004780 int quoted_length = kSpaceForQuotes;
4781 while (read_cursor < end) {
4782 Char c = *(read_cursor++);
4783 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4784 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004785 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004786 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004787 }
4788 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004789 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4790 Object* new_object;
4791 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004792 return new_alloc;
4793 }
4794 StringType* new_string = StringType::cast(new_object);
4795
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004796 Char* write_cursor = reinterpret_cast<Char*>(
4797 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004798 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004799 *(write_cursor++) = '"';
4800
4801 read_cursor = characters.start();
4802 while (read_cursor < end) {
4803 Char c = *(read_cursor++);
4804 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4805 *(write_cursor++) = c;
4806 } else {
4807 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4808 const char* replacement = JsonQuotes +
4809 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4810 for (int i = 0; i < len; i++) {
4811 *write_cursor++ = *replacement++;
4812 }
4813 }
4814 }
4815 *(write_cursor++) = '"';
4816 return new_string;
4817}
4818
4819
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004820template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004821static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4822 int length = characters.length();
4823 Counters::quote_json_char_count.Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004824 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004825 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4826 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004827 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004828 }
4829
4830 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4831 Object* new_object;
4832 if (!new_alloc->ToObject(&new_object)) {
4833 return new_alloc;
4834 }
4835 if (!Heap::new_space()->Contains(new_object)) {
4836 // Even if our string is small enough to fit in new space we still have to
4837 // handle it being allocated in old space as may happen in the third
4838 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4839 // CEntryStub::GenerateCore.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004840 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004841 }
4842 StringType* new_string = StringType::cast(new_object);
4843 ASSERT(Heap::new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004844
4845 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4846 Char* write_cursor = reinterpret_cast<Char*>(
4847 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004848 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004849 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004850
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004851 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004852 const Char* end = read_cursor + length;
4853 while (read_cursor < end) {
4854 Char c = *(read_cursor++);
4855 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4856 *(write_cursor++) = c;
4857 } else {
4858 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4859 const char* replacement = JsonQuotes +
4860 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4861 write_cursor[0] = replacement[0];
4862 if (len > 1) {
4863 write_cursor[1] = replacement[1];
4864 if (len > 2) {
4865 ASSERT(len == 6);
4866 write_cursor[2] = replacement[2];
4867 write_cursor[3] = replacement[3];
4868 write_cursor[4] = replacement[4];
4869 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004870 }
4871 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004872 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004873 }
4874 }
4875 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004876
4877 int final_length = static_cast<int>(
4878 write_cursor - reinterpret_cast<Char*>(
4879 new_string->address() + SeqAsciiString::kHeaderSize));
4880 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4881 final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004882 return new_string;
4883}
4884
4885
4886static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4887 NoHandleAllocation ha;
4888 CONVERT_CHECKED(String, str, args[0]);
4889 if (!str->IsFlat()) {
4890 MaybeObject* try_flatten = str->TryFlatten();
4891 Object* flat;
4892 if (!try_flatten->ToObject(&flat)) {
4893 return try_flatten;
4894 }
4895 str = String::cast(flat);
4896 ASSERT(str->IsFlat());
4897 }
4898 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004899 return QuoteJsonString<uc16, SeqTwoByteString, false>(str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004900 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004901 return QuoteJsonString<char, SeqAsciiString, false>(str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004902 }
4903}
4904
4905
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004906static MaybeObject* Runtime_QuoteJSONStringComma(Arguments args) {
4907 NoHandleAllocation ha;
4908 CONVERT_CHECKED(String, str, args[0]);
4909 if (!str->IsFlat()) {
4910 MaybeObject* try_flatten = str->TryFlatten();
4911 Object* flat;
4912 if (!try_flatten->ToObject(&flat)) {
4913 return try_flatten;
4914 }
4915 str = String::cast(flat);
4916 ASSERT(str->IsFlat());
4917 }
4918 if (str->IsTwoByteRepresentation()) {
4919 return QuoteJsonString<uc16, SeqTwoByteString, true>(str->ToUC16Vector());
4920 } else {
4921 return QuoteJsonString<char, SeqAsciiString, true>(str->ToAsciiVector());
4922 }
4923}
4924
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004925
lrn@chromium.org303ada72010-10-27 09:33:13 +00004926static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004927 NoHandleAllocation ha;
4928
4929 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004930 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004931
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004932 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004933
lrn@chromium.org25156de2010-04-06 13:10:27 +00004934 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4935 double value = StringToInt(s, radix);
4936 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004937}
4938
4939
lrn@chromium.org303ada72010-10-27 09:33:13 +00004940static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004941 NoHandleAllocation ha;
4942 CONVERT_CHECKED(String, str, args[0]);
4943
4944 // ECMA-262 section 15.1.2.3, empty string is NaN
4945 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4946
4947 // Create a number object from the value.
4948 return Heap::NumberFromDouble(value);
4949}
4950
4951
4952static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4953static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4954
4955
4956template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004957MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4958 String* s,
4959 int length,
4960 int input_string_length,
4961 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004962 // We try this twice, once with the assumption that the result is no longer
4963 // than the input and, if that assumption breaks, again with the exact
4964 // length. This may not be pretty, but it is nicer than what was here before
4965 // and I hereby claim my vaffel-is.
4966 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004967 // Allocate the resulting string.
4968 //
4969 // NOTE: This assumes that the upper/lower case of an ascii
4970 // character is also ascii. This is currently the case, but it
4971 // might break in the future if we implement more context and locale
4972 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004973 Object* o;
4974 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4975 ? Heap::AllocateRawAsciiString(length)
4976 : Heap::AllocateRawTwoByteString(length);
4977 if (!maybe_o->ToObject(&o)) return maybe_o;
4978 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004979 String* result = String::cast(o);
4980 bool has_changed_character = false;
4981
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004982 // Convert all characters to upper case, assuming that they will fit
4983 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004984 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004985 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004986 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004987 // We can assume that the string is not empty
4988 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004989 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004990 bool has_next = buffer->has_more();
4991 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004992 int char_length = mapping->get(current, next, chars);
4993 if (char_length == 0) {
4994 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004995 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004996 i++;
4997 } else if (char_length == 1) {
4998 // Common case: converting the letter resulted in one character.
4999 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005000 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005001 has_changed_character = true;
5002 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005003 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005004 // We've assumed that the result would be as long as the
5005 // input but here is a character that converts to several
5006 // characters. No matter, we calculate the exact length
5007 // of the result and try the whole thing again.
5008 //
5009 // Note that this leaves room for optimization. We could just
5010 // memcpy what we already have to the result string. Also,
5011 // the result string is the last object allocated we could
5012 // "realloc" it and probably, in the vast majority of cases,
5013 // extend the existing string to be able to hold the full
5014 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005015 int next_length = 0;
5016 if (has_next) {
5017 next_length = mapping->get(next, 0, chars);
5018 if (next_length == 0) next_length = 1;
5019 }
5020 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005021 while (buffer->has_more()) {
5022 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005023 // NOTE: we use 0 as the next character here because, while
5024 // the next character may affect what a character converts to,
5025 // it does not in any case affect the length of what it convert
5026 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005027 int char_length = mapping->get(current, 0, chars);
5028 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005029 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005030 if (current_length > Smi::kMaxValue) {
5031 Top::context()->mark_out_of_memory();
5032 return Failure::OutOfMemoryException();
5033 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005034 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005035 // Try again with the real length.
5036 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005037 } else {
5038 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005039 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005040 i++;
5041 }
5042 has_changed_character = true;
5043 }
5044 current = next;
5045 }
5046 if (has_changed_character) {
5047 return result;
5048 } else {
5049 // If we didn't actually change anything in doing the conversion
5050 // we simple return the result and let the converted string
5051 // become garbage; there is no reason to keep two identical strings
5052 // alive.
5053 return s;
5054 }
5055}
5056
5057
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005058namespace {
5059
lrn@chromium.org303ada72010-10-27 09:33:13 +00005060static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5061
5062
5063// Given a word and two range boundaries returns a word with high bit
5064// set in every byte iff the corresponding input byte was strictly in
5065// the range (m, n). All the other bits in the result are cleared.
5066// This function is only useful when it can be inlined and the
5067// boundaries are statically known.
5068// Requires: all bytes in the input word and the boundaries must be
5069// ascii (less than 0x7F).
5070static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5071 // Every byte in an ascii string is less than or equal to 0x7F.
5072 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5073 // Use strict inequalities since in edge cases the function could be
5074 // further simplified.
5075 ASSERT(0 < m && m < n && n < 0x7F);
5076 // Has high bit set in every w byte less than n.
5077 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5078 // Has high bit set in every w byte greater than m.
5079 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5080 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5081}
5082
5083
5084enum AsciiCaseConversion {
5085 ASCII_TO_LOWER,
5086 ASCII_TO_UPPER
5087};
5088
5089
5090template <AsciiCaseConversion dir>
5091struct FastAsciiConverter {
5092 static bool Convert(char* dst, char* src, int length) {
5093#ifdef DEBUG
5094 char* saved_dst = dst;
5095 char* saved_src = src;
5096#endif
5097 // We rely on the distance between upper and lower case letters
5098 // being a known power of 2.
5099 ASSERT('a' - 'A' == (1 << 5));
5100 // Boundaries for the range of input characters than require conversion.
5101 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5102 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5103 bool changed = false;
5104 char* const limit = src + length;
5105#ifdef V8_HOST_CAN_READ_UNALIGNED
5106 // Process the prefix of the input that requires no conversion one
5107 // (machine) word at a time.
5108 while (src <= limit - sizeof(uintptr_t)) {
5109 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5110 if (AsciiRangeMask(w, lo, hi) != 0) {
5111 changed = true;
5112 break;
5113 }
5114 *reinterpret_cast<uintptr_t*>(dst) = w;
5115 src += sizeof(uintptr_t);
5116 dst += sizeof(uintptr_t);
5117 }
5118 // Process the remainder of the input performing conversion when
5119 // required one word at a time.
5120 while (src <= limit - sizeof(uintptr_t)) {
5121 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5122 uintptr_t m = AsciiRangeMask(w, lo, hi);
5123 // The mask has high (7th) bit set in every byte that needs
5124 // conversion and we know that the distance between cases is
5125 // 1 << 5.
5126 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5127 src += sizeof(uintptr_t);
5128 dst += sizeof(uintptr_t);
5129 }
5130#endif
5131 // Process the last few bytes of the input (or the whole input if
5132 // unaligned access is not supported).
5133 while (src < limit) {
5134 char c = *src;
5135 if (lo < c && c < hi) {
5136 c ^= (1 << 5);
5137 changed = true;
5138 }
5139 *dst = c;
5140 ++src;
5141 ++dst;
5142 }
5143#ifdef DEBUG
5144 CheckConvert(saved_dst, saved_src, length, changed);
5145#endif
5146 return changed;
5147 }
5148
5149#ifdef DEBUG
5150 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5151 bool expected_changed = false;
5152 for (int i = 0; i < length; i++) {
5153 if (dst[i] == src[i]) continue;
5154 expected_changed = true;
5155 if (dir == ASCII_TO_LOWER) {
5156 ASSERT('A' <= src[i] && src[i] <= 'Z');
5157 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5158 } else {
5159 ASSERT(dir == ASCII_TO_UPPER);
5160 ASSERT('a' <= src[i] && src[i] <= 'z');
5161 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5162 }
5163 }
5164 ASSERT(expected_changed == changed);
5165 }
5166#endif
5167};
5168
5169
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005170struct ToLowerTraits {
5171 typedef unibrow::ToLowercase UnibrowConverter;
5172
lrn@chromium.org303ada72010-10-27 09:33:13 +00005173 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005174};
5175
5176
5177struct ToUpperTraits {
5178 typedef unibrow::ToUppercase UnibrowConverter;
5179
lrn@chromium.org303ada72010-10-27 09:33:13 +00005180 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005181};
5182
5183} // namespace
5184
5185
5186template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005187MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005188 Arguments args,
5189 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005190 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005191 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005192 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005193
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005194 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005195 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005196 if (length == 0) return s;
5197
5198 // Simpler handling of ascii strings.
5199 //
5200 // NOTE: This assumes that the upper/lower case of an ascii
5201 // character is also ascii. This is currently the case, but it
5202 // might break in the future if we implement more context and locale
5203 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005204 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005205 Object* o;
5206 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
5207 if (!maybe_o->ToObject(&o)) return maybe_o;
5208 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005209 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005210 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005211 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005212 return has_changed_character ? result : s;
5213 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005214
lrn@chromium.org303ada72010-10-27 09:33:13 +00005215 Object* answer;
5216 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5217 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5218 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005219 if (answer->IsSmi()) {
5220 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005221 { MaybeObject* maybe_answer =
5222 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5223 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5224 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005225 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005226 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005227}
5228
5229
lrn@chromium.org303ada72010-10-27 09:33:13 +00005230static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005231 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005232}
5233
5234
lrn@chromium.org303ada72010-10-27 09:33:13 +00005235static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005236 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005237}
5238
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005239
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005240static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5241 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5242}
5243
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005244
lrn@chromium.org303ada72010-10-27 09:33:13 +00005245static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005246 NoHandleAllocation ha;
5247 ASSERT(args.length() == 3);
5248
5249 CONVERT_CHECKED(String, s, args[0]);
5250 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5251 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5252
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005253 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005254 int length = s->length();
5255
5256 int left = 0;
5257 if (trimLeft) {
5258 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5259 left++;
5260 }
5261 }
5262
5263 int right = length;
5264 if (trimRight) {
5265 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5266 right--;
5267 }
5268 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005269 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005270}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005271
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005272
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005273template <typename SubjectChar, typename PatternChar>
5274void FindStringIndices(Vector<const SubjectChar> subject,
5275 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005276 ZoneList<int>* indices,
5277 unsigned int limit) {
5278 ASSERT(limit > 0);
5279 // Collect indices of pattern in subject, and the end-of-string index.
5280 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005281 StringSearch<PatternChar, SubjectChar> search(pattern);
5282 int pattern_length = pattern.length();
5283 int index = 0;
5284 while (limit > 0) {
5285 index = search.Search(subject, index);
5286 if (index < 0) return;
5287 indices->Add(index);
5288 index += pattern_length;
5289 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005290 }
5291}
5292
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005293
lrn@chromium.org303ada72010-10-27 09:33:13 +00005294static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005295 ASSERT(args.length() == 3);
5296 HandleScope handle_scope;
5297 CONVERT_ARG_CHECKED(String, subject, 0);
5298 CONVERT_ARG_CHECKED(String, pattern, 1);
5299 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5300
5301 int subject_length = subject->length();
5302 int pattern_length = pattern->length();
5303 RUNTIME_ASSERT(pattern_length > 0);
5304
5305 // The limit can be very large (0xffffffffu), but since the pattern
5306 // isn't empty, we can never create more parts than ~half the length
5307 // of the subject.
5308
5309 if (!subject->IsFlat()) FlattenString(subject);
5310
5311 static const int kMaxInitialListCapacity = 16;
5312
5313 ZoneScope scope(DELETE_ON_EXIT);
5314
5315 // Find (up to limit) indices of separator and end-of-string in subject
5316 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5317 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005318 if (!pattern->IsFlat()) FlattenString(pattern);
5319
5320 // No allocation block.
5321 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005322 AssertNoAllocation nogc;
5323 if (subject->IsAsciiRepresentation()) {
5324 Vector<const char> subject_vector = subject->ToAsciiVector();
5325 if (pattern->IsAsciiRepresentation()) {
5326 FindStringIndices(subject_vector,
5327 pattern->ToAsciiVector(),
5328 &indices,
5329 limit);
5330 } else {
5331 FindStringIndices(subject_vector,
5332 pattern->ToUC16Vector(),
5333 &indices,
5334 limit);
5335 }
5336 } else {
5337 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5338 if (pattern->IsAsciiRepresentation()) {
5339 FindStringIndices(subject_vector,
5340 pattern->ToAsciiVector(),
5341 &indices,
5342 limit);
5343 } else {
5344 FindStringIndices(subject_vector,
5345 pattern->ToUC16Vector(),
5346 &indices,
5347 limit);
5348 }
5349 }
5350 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005351
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005352 if (static_cast<uint32_t>(indices.length()) < limit) {
5353 indices.Add(subject_length);
5354 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005355
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005356 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005357
5358 // Create JSArray of substrings separated by separator.
5359 int part_count = indices.length();
5360
5361 Handle<JSArray> result = Factory::NewJSArray(part_count);
5362 result->set_length(Smi::FromInt(part_count));
5363
5364 ASSERT(result->HasFastElements());
5365
5366 if (part_count == 1 && indices.at(0) == subject_length) {
5367 FixedArray::cast(result->elements())->set(0, *subject);
5368 return *result;
5369 }
5370
5371 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5372 int part_start = 0;
5373 for (int i = 0; i < part_count; i++) {
5374 HandleScope local_loop_handle;
5375 int part_end = indices.at(i);
5376 Handle<String> substring =
5377 Factory::NewSubString(subject, part_start, part_end);
5378 elements->set(i, *substring);
5379 part_start = part_end + pattern_length;
5380 }
5381
5382 return *result;
5383}
5384
5385
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005386// Copies ascii characters to the given fixed array looking up
5387// one-char strings in the cache. Gives up on the first char that is
5388// not in the cache and fills the remainder with smi zeros. Returns
5389// the length of the successfully copied prefix.
5390static int CopyCachedAsciiCharsToArray(const char* chars,
5391 FixedArray* elements,
5392 int length) {
5393 AssertNoAllocation nogc;
5394 FixedArray* ascii_cache = Heap::single_character_string_cache();
5395 Object* undefined = Heap::undefined_value();
5396 int i;
5397 for (i = 0; i < length; ++i) {
5398 Object* value = ascii_cache->get(chars[i]);
5399 if (value == undefined) break;
5400 ASSERT(!Heap::InNewSpace(value));
5401 elements->set(i, value, SKIP_WRITE_BARRIER);
5402 }
5403 if (i < length) {
5404 ASSERT(Smi::FromInt(0) == 0);
5405 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5406 }
5407#ifdef DEBUG
5408 for (int j = 0; j < length; ++j) {
5409 Object* element = elements->get(j);
5410 ASSERT(element == Smi::FromInt(0) ||
5411 (element->IsString() && String::cast(element)->LooksValid()));
5412 }
5413#endif
5414 return i;
5415}
5416
5417
5418// Converts a String to JSArray.
5419// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005420static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005421 HandleScope scope;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005422 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005423 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005424 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005425
5426 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005427 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005428
5429 Handle<FixedArray> elements;
5430 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005431 Object* obj;
5432 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5433 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5434 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005435 elements = Handle<FixedArray>(FixedArray::cast(obj));
5436
5437 Vector<const char> chars = s->ToAsciiVector();
5438 // Note, this will initialize all elements (not only the prefix)
5439 // to prevent GC from seeing partially initialized array.
5440 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5441 *elements,
5442 length);
5443
5444 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005445 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5446 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005447 }
5448 } else {
5449 elements = Factory::NewFixedArray(length);
5450 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005451 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5452 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005453 }
5454 }
5455
5456#ifdef DEBUG
5457 for (int i = 0; i < length; ++i) {
5458 ASSERT(String::cast(elements->get(i))->length() == 1);
5459 }
5460#endif
5461
5462 return *Factory::NewJSArrayWithElements(elements);
5463}
5464
5465
lrn@chromium.org303ada72010-10-27 09:33:13 +00005466static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005467 NoHandleAllocation ha;
5468 ASSERT(args.length() == 1);
5469 CONVERT_CHECKED(String, value, args[0]);
5470 return value->ToObject();
5471}
5472
5473
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005474bool Runtime::IsUpperCaseChar(uint16_t ch) {
5475 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5476 int char_length = to_upper_mapping.get(ch, 0, chars);
5477 return char_length == 0;
5478}
5479
5480
lrn@chromium.org303ada72010-10-27 09:33:13 +00005481static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005482 NoHandleAllocation ha;
5483 ASSERT(args.length() == 1);
5484
5485 Object* number = args[0];
5486 RUNTIME_ASSERT(number->IsNumber());
5487
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005488 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005489}
5490
5491
lrn@chromium.org303ada72010-10-27 09:33:13 +00005492static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005493 NoHandleAllocation ha;
5494 ASSERT(args.length() == 1);
5495
5496 Object* number = args[0];
5497 RUNTIME_ASSERT(number->IsNumber());
5498
5499 return Heap::NumberToString(number, false);
5500}
5501
5502
lrn@chromium.org303ada72010-10-27 09:33:13 +00005503static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005504 NoHandleAllocation ha;
5505 ASSERT(args.length() == 1);
5506
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005507 CONVERT_DOUBLE_CHECKED(number, args[0]);
5508
5509 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5510 if (number > 0 && number <= Smi::kMaxValue) {
5511 return Smi::FromInt(static_cast<int>(number));
5512 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005513 return Heap::NumberFromDouble(DoubleToInteger(number));
5514}
5515
5516
lrn@chromium.org303ada72010-10-27 09:33:13 +00005517static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005518 NoHandleAllocation ha;
5519 ASSERT(args.length() == 1);
5520
5521 CONVERT_DOUBLE_CHECKED(number, args[0]);
5522
5523 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5524 if (number > 0 && number <= Smi::kMaxValue) {
5525 return Smi::FromInt(static_cast<int>(number));
5526 }
5527
5528 double double_value = DoubleToInteger(number);
5529 // Map both -0 and +0 to +0.
5530 if (double_value == 0) double_value = 0;
5531
5532 return Heap::NumberFromDouble(double_value);
5533}
5534
5535
lrn@chromium.org303ada72010-10-27 09:33:13 +00005536static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005537 NoHandleAllocation ha;
5538 ASSERT(args.length() == 1);
5539
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005540 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005541 return Heap::NumberFromUint32(number);
5542}
5543
5544
lrn@chromium.org303ada72010-10-27 09:33:13 +00005545static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005546 NoHandleAllocation ha;
5547 ASSERT(args.length() == 1);
5548
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005549 CONVERT_DOUBLE_CHECKED(number, args[0]);
5550
5551 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5552 if (number > 0 && number <= Smi::kMaxValue) {
5553 return Smi::FromInt(static_cast<int>(number));
5554 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005555 return Heap::NumberFromInt32(DoubleToInt32(number));
5556}
5557
5558
ager@chromium.org870a0b62008-11-04 11:43:05 +00005559// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5560// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005561static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005562 NoHandleAllocation ha;
5563 ASSERT(args.length() == 1);
5564
5565 Object* obj = args[0];
5566 if (obj->IsSmi()) {
5567 return obj;
5568 }
5569 if (obj->IsHeapNumber()) {
5570 double value = HeapNumber::cast(obj)->value();
5571 int int_value = FastD2I(value);
5572 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5573 return Smi::FromInt(int_value);
5574 }
5575 }
5576 return Heap::nan_value();
5577}
5578
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005579
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005580static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5581 NoHandleAllocation ha;
5582 ASSERT(args.length() == 0);
5583 return Heap::AllocateHeapNumber(0);
5584}
5585
5586
lrn@chromium.org303ada72010-10-27 09:33:13 +00005587static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005588 NoHandleAllocation ha;
5589 ASSERT(args.length() == 2);
5590
5591 CONVERT_DOUBLE_CHECKED(x, args[0]);
5592 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005593 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005594}
5595
5596
lrn@chromium.org303ada72010-10-27 09:33:13 +00005597static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005598 NoHandleAllocation ha;
5599 ASSERT(args.length() == 2);
5600
5601 CONVERT_DOUBLE_CHECKED(x, args[0]);
5602 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005603 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005604}
5605
5606
lrn@chromium.org303ada72010-10-27 09:33:13 +00005607static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005608 NoHandleAllocation ha;
5609 ASSERT(args.length() == 2);
5610
5611 CONVERT_DOUBLE_CHECKED(x, args[0]);
5612 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005613 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005614}
5615
5616
lrn@chromium.org303ada72010-10-27 09:33:13 +00005617static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005618 NoHandleAllocation ha;
5619 ASSERT(args.length() == 1);
5620
5621 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005622 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005623}
5624
5625
lrn@chromium.org303ada72010-10-27 09:33:13 +00005626static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005627 NoHandleAllocation ha;
5628 ASSERT(args.length() == 0);
5629
5630 return Heap::NumberFromDouble(9876543210.0);
5631}
5632
5633
lrn@chromium.org303ada72010-10-27 09:33:13 +00005634static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005635 NoHandleAllocation ha;
5636 ASSERT(args.length() == 2);
5637
5638 CONVERT_DOUBLE_CHECKED(x, args[0]);
5639 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005640 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005641}
5642
5643
lrn@chromium.org303ada72010-10-27 09:33:13 +00005644static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005645 NoHandleAllocation ha;
5646 ASSERT(args.length() == 2);
5647
5648 CONVERT_DOUBLE_CHECKED(x, args[0]);
5649 CONVERT_DOUBLE_CHECKED(y, args[1]);
5650
ager@chromium.org3811b432009-10-28 14:53:37 +00005651 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005652 // NumberFromDouble may return a Smi instead of a Number object
5653 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005654}
5655
5656
lrn@chromium.org303ada72010-10-27 09:33:13 +00005657static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005658 NoHandleAllocation ha;
5659 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005660 CONVERT_CHECKED(String, str1, args[0]);
5661 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005662 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005663 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005664}
5665
5666
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005667template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005668static inline void StringBuilderConcatHelper(String* special,
5669 sinkchar* sink,
5670 FixedArray* fixed_array,
5671 int array_length) {
5672 int position = 0;
5673 for (int i = 0; i < array_length; i++) {
5674 Object* element = fixed_array->get(i);
5675 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005676 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005677 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005678 int pos;
5679 int len;
5680 if (encoded_slice > 0) {
5681 // Position and length encoded in one smi.
5682 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5683 len = StringBuilderSubstringLength::decode(encoded_slice);
5684 } else {
5685 // Position and length encoded in two smis.
5686 Object* obj = fixed_array->get(++i);
5687 ASSERT(obj->IsSmi());
5688 pos = Smi::cast(obj)->value();
5689 len = -encoded_slice;
5690 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005691 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005692 sink + position,
5693 pos,
5694 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005695 position += len;
5696 } else {
5697 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005698 int element_length = string->length();
5699 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005700 position += element_length;
5701 }
5702 }
5703}
5704
5705
lrn@chromium.org303ada72010-10-27 09:33:13 +00005706static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005707 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005708 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005709 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005710 if (!args[1]->IsSmi()) {
5711 Top::context()->mark_out_of_memory();
5712 return Failure::OutOfMemoryException();
5713 }
5714 int array_length = Smi::cast(args[1])->value();
5715 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005716
5717 // This assumption is used by the slice encoding in one or two smis.
5718 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5719
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005720 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005721 if (!array->HasFastElements()) {
5722 return Top::Throw(Heap::illegal_argument_symbol());
5723 }
5724 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005725 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005726 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005727 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005728
5729 if (array_length == 0) {
5730 return Heap::empty_string();
5731 } else if (array_length == 1) {
5732 Object* first = fixed_array->get(0);
5733 if (first->IsString()) return first;
5734 }
5735
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005736 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005737 int position = 0;
5738 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005739 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005740 Object* elt = fixed_array->get(i);
5741 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005742 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005743 int smi_value = Smi::cast(elt)->value();
5744 int pos;
5745 int len;
5746 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005747 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005748 pos = StringBuilderSubstringPosition::decode(smi_value);
5749 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005750 } else {
5751 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005752 len = -smi_value;
5753 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005754 i++;
5755 if (i >= array_length) {
5756 return Top::Throw(Heap::illegal_argument_symbol());
5757 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005758 Object* next_smi = fixed_array->get(i);
5759 if (!next_smi->IsSmi()) {
5760 return Top::Throw(Heap::illegal_argument_symbol());
5761 }
5762 pos = Smi::cast(next_smi)->value();
5763 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005764 return Top::Throw(Heap::illegal_argument_symbol());
5765 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005766 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005767 ASSERT(pos >= 0);
5768 ASSERT(len >= 0);
5769 if (pos > special_length || len > special_length - pos) {
5770 return Top::Throw(Heap::illegal_argument_symbol());
5771 }
5772 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005773 } else if (elt->IsString()) {
5774 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005775 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005776 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005777 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005778 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005779 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005780 } else {
5781 return Top::Throw(Heap::illegal_argument_symbol());
5782 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005783 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005784 Top::context()->mark_out_of_memory();
5785 return Failure::OutOfMemoryException();
5786 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005787 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005788 }
5789
5790 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005791 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005792
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005793 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005794 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5795 if (!maybe_object->ToObject(&object)) return maybe_object;
5796 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005797 SeqAsciiString* answer = SeqAsciiString::cast(object);
5798 StringBuilderConcatHelper(special,
5799 answer->GetChars(),
5800 fixed_array,
5801 array_length);
5802 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005803 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005804 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5805 if (!maybe_object->ToObject(&object)) return maybe_object;
5806 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005807 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5808 StringBuilderConcatHelper(special,
5809 answer->GetChars(),
5810 fixed_array,
5811 array_length);
5812 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005813 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005814}
5815
5816
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005817static MaybeObject* Runtime_StringBuilderJoin(Arguments args) {
5818 NoHandleAllocation ha;
5819 ASSERT(args.length() == 3);
5820 CONVERT_CHECKED(JSArray, array, args[0]);
5821 if (!args[1]->IsSmi()) {
5822 Top::context()->mark_out_of_memory();
5823 return Failure::OutOfMemoryException();
5824 }
5825 int array_length = Smi::cast(args[1])->value();
5826 CONVERT_CHECKED(String, separator, args[2]);
5827
5828 if (!array->HasFastElements()) {
5829 return Top::Throw(Heap::illegal_argument_symbol());
5830 }
5831 FixedArray* fixed_array = FixedArray::cast(array->elements());
5832 if (fixed_array->length() < array_length) {
5833 array_length = fixed_array->length();
5834 }
5835
5836 if (array_length == 0) {
5837 return Heap::empty_string();
5838 } else if (array_length == 1) {
5839 Object* first = fixed_array->get(0);
5840 if (first->IsString()) return first;
5841 }
5842
5843 int separator_length = separator->length();
5844 int max_nof_separators =
5845 (String::kMaxLength + separator_length - 1) / separator_length;
5846 if (max_nof_separators < (array_length - 1)) {
5847 Top::context()->mark_out_of_memory();
5848 return Failure::OutOfMemoryException();
5849 }
5850 int length = (array_length - 1) * separator_length;
5851 for (int i = 0; i < array_length; i++) {
5852 Object* element_obj = fixed_array->get(i);
5853 if (!element_obj->IsString()) {
5854 // TODO(1161): handle this case.
5855 return Top::Throw(Heap::illegal_argument_symbol());
5856 }
5857 String* element = String::cast(element_obj);
5858 int increment = element->length();
5859 if (increment > String::kMaxLength - length) {
5860 Top::context()->mark_out_of_memory();
5861 return Failure::OutOfMemoryException();
5862 }
5863 length += increment;
5864 }
5865
5866 Object* object;
5867 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5868 if (!maybe_object->ToObject(&object)) return maybe_object;
5869 }
5870 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5871
5872 uc16* sink = answer->GetChars();
5873#ifdef DEBUG
5874 uc16* end = sink + length;
5875#endif
5876
5877 String* first = String::cast(fixed_array->get(0));
5878 int first_length = first->length();
5879 String::WriteToFlat(first, sink, 0, first_length);
5880 sink += first_length;
5881
5882 for (int i = 1; i < array_length; i++) {
5883 ASSERT(sink + separator_length <= end);
5884 String::WriteToFlat(separator, sink, 0, separator_length);
5885 sink += separator_length;
5886
5887 String* element = String::cast(fixed_array->get(i));
5888 int element_length = element->length();
5889 ASSERT(sink + element_length <= end);
5890 String::WriteToFlat(element, sink, 0, element_length);
5891 sink += element_length;
5892 }
5893 ASSERT(sink == end);
5894
5895 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
5896 return answer;
5897}
5898
5899
lrn@chromium.org303ada72010-10-27 09:33:13 +00005900static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005901 NoHandleAllocation ha;
5902 ASSERT(args.length() == 2);
5903
5904 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5905 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5906 return Heap::NumberFromInt32(x | y);
5907}
5908
5909
lrn@chromium.org303ada72010-10-27 09:33:13 +00005910static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005911 NoHandleAllocation ha;
5912 ASSERT(args.length() == 2);
5913
5914 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5915 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5916 return Heap::NumberFromInt32(x & y);
5917}
5918
5919
lrn@chromium.org303ada72010-10-27 09:33:13 +00005920static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921 NoHandleAllocation ha;
5922 ASSERT(args.length() == 2);
5923
5924 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5925 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5926 return Heap::NumberFromInt32(x ^ y);
5927}
5928
5929
lrn@chromium.org303ada72010-10-27 09:33:13 +00005930static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005931 NoHandleAllocation ha;
5932 ASSERT(args.length() == 1);
5933
5934 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5935 return Heap::NumberFromInt32(~x);
5936}
5937
5938
lrn@chromium.org303ada72010-10-27 09:33:13 +00005939static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005940 NoHandleAllocation ha;
5941 ASSERT(args.length() == 2);
5942
5943 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5944 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5945 return Heap::NumberFromInt32(x << (y & 0x1f));
5946}
5947
5948
lrn@chromium.org303ada72010-10-27 09:33:13 +00005949static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005950 NoHandleAllocation ha;
5951 ASSERT(args.length() == 2);
5952
5953 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5954 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5955 return Heap::NumberFromUint32(x >> (y & 0x1f));
5956}
5957
5958
lrn@chromium.org303ada72010-10-27 09:33:13 +00005959static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005960 NoHandleAllocation ha;
5961 ASSERT(args.length() == 2);
5962
5963 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5964 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5965 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5966}
5967
5968
lrn@chromium.org303ada72010-10-27 09:33:13 +00005969static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005970 NoHandleAllocation ha;
5971 ASSERT(args.length() == 2);
5972
5973 CONVERT_DOUBLE_CHECKED(x, args[0]);
5974 CONVERT_DOUBLE_CHECKED(y, args[1]);
5975 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5976 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5977 if (x == y) return Smi::FromInt(EQUAL);
5978 Object* result;
5979 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5980 result = Smi::FromInt(EQUAL);
5981 } else {
5982 result = Smi::FromInt(NOT_EQUAL);
5983 }
5984 return result;
5985}
5986
5987
lrn@chromium.org303ada72010-10-27 09:33:13 +00005988static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989 NoHandleAllocation ha;
5990 ASSERT(args.length() == 2);
5991
5992 CONVERT_CHECKED(String, x, args[0]);
5993 CONVERT_CHECKED(String, y, args[1]);
5994
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005995 bool not_equal = !x->Equals(y);
5996 // This is slightly convoluted because the value that signifies
5997 // equality is 0 and inequality is 1 so we have to negate the result
5998 // from String::Equals.
5999 ASSERT(not_equal == 0 || not_equal == 1);
6000 STATIC_CHECK(EQUAL == 0);
6001 STATIC_CHECK(NOT_EQUAL == 1);
6002 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006003}
6004
6005
lrn@chromium.org303ada72010-10-27 09:33:13 +00006006static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006007 NoHandleAllocation ha;
6008 ASSERT(args.length() == 3);
6009
6010 CONVERT_DOUBLE_CHECKED(x, args[0]);
6011 CONVERT_DOUBLE_CHECKED(y, args[1]);
6012 if (isnan(x) || isnan(y)) return args[2];
6013 if (x == y) return Smi::FromInt(EQUAL);
6014 if (isless(x, y)) return Smi::FromInt(LESS);
6015 return Smi::FromInt(GREATER);
6016}
6017
6018
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006019// Compare two Smis as if they were converted to strings and then
6020// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006021static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006022 NoHandleAllocation ha;
6023 ASSERT(args.length() == 2);
6024
6025 // Arrays for the individual characters of the two Smis. Smis are
6026 // 31 bit integers and 10 decimal digits are therefore enough.
6027 static int x_elms[10];
6028 static int y_elms[10];
6029
6030 // Extract the integer values from the Smis.
6031 CONVERT_CHECKED(Smi, x, args[0]);
6032 CONVERT_CHECKED(Smi, y, args[1]);
6033 int x_value = x->value();
6034 int y_value = y->value();
6035
6036 // If the integers are equal so are the string representations.
6037 if (x_value == y_value) return Smi::FromInt(EQUAL);
6038
6039 // If one of the integers are zero the normal integer order is the
6040 // same as the lexicographic order of the string representations.
6041 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6042
ager@chromium.org32912102009-01-16 10:38:43 +00006043 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006044 // smallest because the char code of '-' is less than the char code
6045 // of any digit. Otherwise, we make both values positive.
6046 if (x_value < 0 || y_value < 0) {
6047 if (y_value >= 0) return Smi::FromInt(LESS);
6048 if (x_value >= 0) return Smi::FromInt(GREATER);
6049 x_value = -x_value;
6050 y_value = -y_value;
6051 }
6052
6053 // Convert the integers to arrays of their decimal digits.
6054 int x_index = 0;
6055 int y_index = 0;
6056 while (x_value > 0) {
6057 x_elms[x_index++] = x_value % 10;
6058 x_value /= 10;
6059 }
6060 while (y_value > 0) {
6061 y_elms[y_index++] = y_value % 10;
6062 y_value /= 10;
6063 }
6064
6065 // Loop through the arrays of decimal digits finding the first place
6066 // where they differ.
6067 while (--x_index >= 0 && --y_index >= 0) {
6068 int diff = x_elms[x_index] - y_elms[y_index];
6069 if (diff != 0) return Smi::FromInt(diff);
6070 }
6071
6072 // If one array is a suffix of the other array, the longest array is
6073 // the representation of the largest of the Smis in the
6074 // lexicographic ordering.
6075 return Smi::FromInt(x_index - y_index);
6076}
6077
6078
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006079static Object* StringInputBufferCompare(String* x, String* y) {
6080 static StringInputBuffer bufx;
6081 static StringInputBuffer bufy;
6082 bufx.Reset(x);
6083 bufy.Reset(y);
6084 while (bufx.has_more() && bufy.has_more()) {
6085 int d = bufx.GetNext() - bufy.GetNext();
6086 if (d < 0) return Smi::FromInt(LESS);
6087 else if (d > 0) return Smi::FromInt(GREATER);
6088 }
6089
6090 // x is (non-trivial) prefix of y:
6091 if (bufy.has_more()) return Smi::FromInt(LESS);
6092 // y is prefix of x:
6093 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6094}
6095
6096
6097static Object* FlatStringCompare(String* x, String* y) {
6098 ASSERT(x->IsFlat());
6099 ASSERT(y->IsFlat());
6100 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6101 int prefix_length = x->length();
6102 if (y->length() < prefix_length) {
6103 prefix_length = y->length();
6104 equal_prefix_result = Smi::FromInt(GREATER);
6105 } else if (y->length() > prefix_length) {
6106 equal_prefix_result = Smi::FromInt(LESS);
6107 }
6108 int r;
6109 if (x->IsAsciiRepresentation()) {
6110 Vector<const char> x_chars = x->ToAsciiVector();
6111 if (y->IsAsciiRepresentation()) {
6112 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006113 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006114 } else {
6115 Vector<const uc16> y_chars = y->ToUC16Vector();
6116 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6117 }
6118 } else {
6119 Vector<const uc16> x_chars = x->ToUC16Vector();
6120 if (y->IsAsciiRepresentation()) {
6121 Vector<const char> y_chars = y->ToAsciiVector();
6122 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6123 } else {
6124 Vector<const uc16> y_chars = y->ToUC16Vector();
6125 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6126 }
6127 }
6128 Object* result;
6129 if (r == 0) {
6130 result = equal_prefix_result;
6131 } else {
6132 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6133 }
6134 ASSERT(result == StringInputBufferCompare(x, y));
6135 return result;
6136}
6137
6138
lrn@chromium.org303ada72010-10-27 09:33:13 +00006139static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006140 NoHandleAllocation ha;
6141 ASSERT(args.length() == 2);
6142
6143 CONVERT_CHECKED(String, x, args[0]);
6144 CONVERT_CHECKED(String, y, args[1]);
6145
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006146 Counters::string_compare_runtime.Increment();
6147
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006148 // A few fast case tests before we flatten.
6149 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006150 if (y->length() == 0) {
6151 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006152 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006153 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006154 return Smi::FromInt(LESS);
6155 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006156
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006157 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006158 if (d < 0) return Smi::FromInt(LESS);
6159 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006160
lrn@chromium.org303ada72010-10-27 09:33:13 +00006161 Object* obj;
6162 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
6163 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6164 }
6165 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
6166 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6167 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006168
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006169 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
6170 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006171}
6172
6173
lrn@chromium.org303ada72010-10-27 09:33:13 +00006174static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006175 NoHandleAllocation ha;
6176 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006177 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006178
6179 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006180 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006181}
6182
6183
lrn@chromium.org303ada72010-10-27 09:33:13 +00006184static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006185 NoHandleAllocation ha;
6186 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006187 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006188
6189 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006190 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006191}
6192
6193
lrn@chromium.org303ada72010-10-27 09:33:13 +00006194static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006195 NoHandleAllocation ha;
6196 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006197 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006198
6199 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006200 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006201}
6202
6203
lrn@chromium.org303ada72010-10-27 09:33:13 +00006204static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006205 NoHandleAllocation ha;
6206 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006207 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006208
6209 CONVERT_DOUBLE_CHECKED(x, args[0]);
6210 CONVERT_DOUBLE_CHECKED(y, args[1]);
6211 double result;
6212 if (isinf(x) && isinf(y)) {
6213 // Make sure that the result in case of two infinite arguments
6214 // is a multiple of Pi / 4. The sign of the result is determined
6215 // by the first argument (x) and the sign of the second argument
6216 // determines the multiplier: one or three.
6217 static double kPiDividedBy4 = 0.78539816339744830962;
6218 int multiplier = (x < 0) ? -1 : 1;
6219 if (y < 0) multiplier *= 3;
6220 result = multiplier * kPiDividedBy4;
6221 } else {
6222 result = atan2(x, y);
6223 }
6224 return Heap::AllocateHeapNumber(result);
6225}
6226
6227
lrn@chromium.org303ada72010-10-27 09:33:13 +00006228static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006229 NoHandleAllocation ha;
6230 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006231 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006232
6233 CONVERT_DOUBLE_CHECKED(x, args[0]);
6234 return Heap::NumberFromDouble(ceiling(x));
6235}
6236
6237
lrn@chromium.org303ada72010-10-27 09:33:13 +00006238static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006239 NoHandleAllocation ha;
6240 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006241 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006242
6243 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006244 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006245}
6246
6247
lrn@chromium.org303ada72010-10-27 09:33:13 +00006248static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006249 NoHandleAllocation ha;
6250 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006251 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006252
6253 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006254 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006255}
6256
6257
lrn@chromium.org303ada72010-10-27 09:33:13 +00006258static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006259 NoHandleAllocation ha;
6260 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006261 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006262
6263 CONVERT_DOUBLE_CHECKED(x, args[0]);
6264 return Heap::NumberFromDouble(floor(x));
6265}
6266
6267
lrn@chromium.org303ada72010-10-27 09:33:13 +00006268static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006269 NoHandleAllocation ha;
6270 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006271 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006272
6273 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006274 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006275}
6276
6277
lrn@chromium.org303ada72010-10-27 09:33:13 +00006278static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006279 NoHandleAllocation ha;
6280 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006281 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006282
6283 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006284
6285 // If the second argument is a smi, it is much faster to call the
6286 // custom powi() function than the generic pow().
6287 if (args[1]->IsSmi()) {
6288 int y = Smi::cast(args[1])->value();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006289 return Heap::NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006290 }
6291
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006292 CONVERT_DOUBLE_CHECKED(y, args[1]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006293 return Heap::AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006294}
6295
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006296// Fast version of Math.pow if we know that y is not an integer and
6297// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006298static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006299 NoHandleAllocation ha;
6300 ASSERT(args.length() == 2);
6301 CONVERT_DOUBLE_CHECKED(x, args[0]);
6302 CONVERT_DOUBLE_CHECKED(y, args[1]);
6303 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006304 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006305 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006306 return Heap::nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006307 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006308 return Heap::AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006309 }
6310}
6311
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006312
lrn@chromium.org303ada72010-10-27 09:33:13 +00006313static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006314 NoHandleAllocation ha;
6315 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006316 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006317
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006318 if (!args[0]->IsHeapNumber()) {
6319 // Must be smi. Return the argument unchanged for all the other types
6320 // to make fuzz-natives test happy.
6321 return args[0];
6322 }
6323
6324 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6325
6326 double value = number->value();
6327 int exponent = number->get_exponent();
6328 int sign = number->get_sign();
6329
6330 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6331 // should be rounded to 2^30, which is not smi.
6332 if (!sign && exponent <= kSmiValueSize - 3) {
6333 return Smi::FromInt(static_cast<int>(value + 0.5));
6334 }
6335
6336 // If the magnitude is big enough, there's no place for fraction part. If we
6337 // try to add 0.5 to this number, 1.0 will be added instead.
6338 if (exponent >= 52) {
6339 return number;
6340 }
6341
6342 if (sign && value >= -0.5) return Heap::minus_zero_value();
6343
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006344 // Do not call NumberFromDouble() to avoid extra checks.
6345 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006346}
6347
6348
lrn@chromium.org303ada72010-10-27 09:33:13 +00006349static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006350 NoHandleAllocation ha;
6351 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006352 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006353
6354 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006355 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006356}
6357
6358
lrn@chromium.org303ada72010-10-27 09:33:13 +00006359static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006360 NoHandleAllocation ha;
6361 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006362 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006363
6364 CONVERT_DOUBLE_CHECKED(x, args[0]);
6365 return Heap::AllocateHeapNumber(sqrt(x));
6366}
6367
6368
lrn@chromium.org303ada72010-10-27 09:33:13 +00006369static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006370 NoHandleAllocation ha;
6371 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006372 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006373
6374 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006375 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006376}
6377
6378
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006379static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006380 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6381 181, 212, 243, 273, 304, 334};
6382 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6383 182, 213, 244, 274, 305, 335};
6384
6385 year += month / 12;
6386 month %= 12;
6387 if (month < 0) {
6388 year--;
6389 month += 12;
6390 }
6391
6392 ASSERT(month >= 0);
6393 ASSERT(month < 12);
6394
6395 // year_delta is an arbitrary number such that:
6396 // a) year_delta = -1 (mod 400)
6397 // b) year + year_delta > 0 for years in the range defined by
6398 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6399 // Jan 1 1970. This is required so that we don't run into integer
6400 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006401 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006402 // operations.
6403 static const int year_delta = 399999;
6404 static const int base_day = 365 * (1970 + year_delta) +
6405 (1970 + year_delta) / 4 -
6406 (1970 + year_delta) / 100 +
6407 (1970 + year_delta) / 400;
6408
6409 int year1 = year + year_delta;
6410 int day_from_year = 365 * year1 +
6411 year1 / 4 -
6412 year1 / 100 +
6413 year1 / 400 -
6414 base_day;
6415
6416 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006417 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006418 }
6419
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006420 return day_from_year + day_from_month_leap[month] + day - 1;
6421}
6422
6423
lrn@chromium.org303ada72010-10-27 09:33:13 +00006424static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006425 NoHandleAllocation ha;
6426 ASSERT(args.length() == 3);
6427
6428 CONVERT_SMI_CHECKED(year, args[0]);
6429 CONVERT_SMI_CHECKED(month, args[1]);
6430 CONVERT_SMI_CHECKED(date, args[2]);
6431
6432 return Smi::FromInt(MakeDay(year, month, date));
6433}
6434
6435
6436static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6437static const int kDaysIn4Years = 4 * 365 + 1;
6438static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6439static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6440static const int kDays1970to2000 = 30 * 365 + 7;
6441static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6442 kDays1970to2000;
6443static const int kYearsOffset = 400000;
6444
6445static const char kDayInYear[] = {
6446 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6447 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6448 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6449 22, 23, 24, 25, 26, 27, 28,
6450 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6451 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6452 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6453 22, 23, 24, 25, 26, 27, 28, 29, 30,
6454 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6455 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6456 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6457 22, 23, 24, 25, 26, 27, 28, 29, 30,
6458 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6459 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6460 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6461 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6462 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6463 22, 23, 24, 25, 26, 27, 28, 29, 30,
6464 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6465 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6466 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6467 22, 23, 24, 25, 26, 27, 28, 29, 30,
6468 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6469 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6470
6471 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6472 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6473 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6474 22, 23, 24, 25, 26, 27, 28,
6475 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6476 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6477 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6478 22, 23, 24, 25, 26, 27, 28, 29, 30,
6479 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6480 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6481 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6482 22, 23, 24, 25, 26, 27, 28, 29, 30,
6483 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6484 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6485 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6486 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6487 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6488 22, 23, 24, 25, 26, 27, 28, 29, 30,
6489 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6490 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6491 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6492 22, 23, 24, 25, 26, 27, 28, 29, 30,
6493 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6494 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6495
6496 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6497 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6498 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6499 22, 23, 24, 25, 26, 27, 28, 29,
6500 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6501 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6502 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6503 22, 23, 24, 25, 26, 27, 28, 29, 30,
6504 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6505 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6506 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6507 22, 23, 24, 25, 26, 27, 28, 29, 30,
6508 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6509 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6510 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6511 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6512 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6513 22, 23, 24, 25, 26, 27, 28, 29, 30,
6514 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6515 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6516 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6517 22, 23, 24, 25, 26, 27, 28, 29, 30,
6518 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6519 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6520
6521 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6522 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6523 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6524 22, 23, 24, 25, 26, 27, 28,
6525 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6526 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6527 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6528 22, 23, 24, 25, 26, 27, 28, 29, 30,
6529 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6530 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6531 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6532 22, 23, 24, 25, 26, 27, 28, 29, 30,
6533 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6534 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6535 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6536 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6537 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6538 22, 23, 24, 25, 26, 27, 28, 29, 30,
6539 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6540 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6541 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6542 22, 23, 24, 25, 26, 27, 28, 29, 30,
6543 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6544 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6545
6546static const char kMonthInYear[] = {
6547 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6548 0, 0, 0, 0, 0, 0,
6549 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6550 1, 1, 1,
6551 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6552 2, 2, 2, 2, 2, 2,
6553 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6554 3, 3, 3, 3, 3,
6555 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6556 4, 4, 4, 4, 4, 4,
6557 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6558 5, 5, 5, 5, 5,
6559 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6560 6, 6, 6, 6, 6, 6,
6561 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6562 7, 7, 7, 7, 7, 7,
6563 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6564 8, 8, 8, 8, 8,
6565 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6566 9, 9, 9, 9, 9, 9,
6567 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6568 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6569 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6570 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6571
6572 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6573 0, 0, 0, 0, 0, 0,
6574 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6575 1, 1, 1,
6576 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6577 2, 2, 2, 2, 2, 2,
6578 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6579 3, 3, 3, 3, 3,
6580 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6581 4, 4, 4, 4, 4, 4,
6582 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6583 5, 5, 5, 5, 5,
6584 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6585 6, 6, 6, 6, 6, 6,
6586 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6587 7, 7, 7, 7, 7, 7,
6588 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6589 8, 8, 8, 8, 8,
6590 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6591 9, 9, 9, 9, 9, 9,
6592 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6593 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6594 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6595 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6596
6597 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6598 0, 0, 0, 0, 0, 0,
6599 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6600 1, 1, 1, 1,
6601 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6602 2, 2, 2, 2, 2, 2,
6603 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6604 3, 3, 3, 3, 3,
6605 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6606 4, 4, 4, 4, 4, 4,
6607 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6608 5, 5, 5, 5, 5,
6609 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6610 6, 6, 6, 6, 6, 6,
6611 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6612 7, 7, 7, 7, 7, 7,
6613 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6614 8, 8, 8, 8, 8,
6615 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6616 9, 9, 9, 9, 9, 9,
6617 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6618 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6619 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6620 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6621
6622 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6623 0, 0, 0, 0, 0, 0,
6624 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6625 1, 1, 1,
6626 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6627 2, 2, 2, 2, 2, 2,
6628 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6629 3, 3, 3, 3, 3,
6630 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6631 4, 4, 4, 4, 4, 4,
6632 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6633 5, 5, 5, 5, 5,
6634 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6635 6, 6, 6, 6, 6, 6,
6636 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6637 7, 7, 7, 7, 7, 7,
6638 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6639 8, 8, 8, 8, 8,
6640 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6641 9, 9, 9, 9, 9, 9,
6642 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6643 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6644 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6645 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6646
6647
6648// This function works for dates from 1970 to 2099.
6649static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006650 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006651#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006652 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006653#endif
6654
6655 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6656 date %= kDaysIn4Years;
6657
6658 month = kMonthInYear[date];
6659 day = kDayInYear[date];
6660
6661 ASSERT(MakeDay(year, month, day) == save_date);
6662}
6663
6664
6665static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006666 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006667#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006668 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006669#endif
6670
6671 date += kDaysOffset;
6672 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6673 date %= kDaysIn400Years;
6674
6675 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6676
6677 date--;
6678 int yd1 = date / kDaysIn100Years;
6679 date %= kDaysIn100Years;
6680 year += 100 * yd1;
6681
6682 date++;
6683 int yd2 = date / kDaysIn4Years;
6684 date %= kDaysIn4Years;
6685 year += 4 * yd2;
6686
6687 date--;
6688 int yd3 = date / 365;
6689 date %= 365;
6690 year += yd3;
6691
6692 bool is_leap = (!yd1 || yd2) && !yd3;
6693
6694 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006695 ASSERT(is_leap || (date >= 0));
6696 ASSERT((date < 365) || (is_leap && (date < 366)));
6697 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6698 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6699 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006700
6701 if (is_leap) {
6702 day = kDayInYear[2*365 + 1 + date];
6703 month = kMonthInYear[2*365 + 1 + date];
6704 } else {
6705 day = kDayInYear[date];
6706 month = kMonthInYear[date];
6707 }
6708
6709 ASSERT(MakeDay(year, month, day) == save_date);
6710}
6711
6712
6713static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006714 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006715 if (date >= 0 && date < 32 * kDaysIn4Years) {
6716 DateYMDFromTimeAfter1970(date, year, month, day);
6717 } else {
6718 DateYMDFromTimeSlow(date, year, month, day);
6719 }
6720}
6721
6722
lrn@chromium.org303ada72010-10-27 09:33:13 +00006723static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006724 NoHandleAllocation ha;
6725 ASSERT(args.length() == 2);
6726
6727 CONVERT_DOUBLE_CHECKED(t, args[0]);
6728 CONVERT_CHECKED(JSArray, res_array, args[1]);
6729
6730 int year, month, day;
6731 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6732
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006733 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6734 FixedArray* elms = FixedArray::cast(res_array->elements());
6735 RUNTIME_ASSERT(elms->length() == 3);
6736
6737 elms->set(0, Smi::FromInt(year));
6738 elms->set(1, Smi::FromInt(month));
6739 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006740
6741 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006742}
6743
6744
lrn@chromium.org303ada72010-10-27 09:33:13 +00006745static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006746 NoHandleAllocation ha;
6747 ASSERT(args.length() == 3);
6748
6749 JSFunction* callee = JSFunction::cast(args[0]);
6750 Object** parameters = reinterpret_cast<Object**>(args[1]);
6751 const int length = Smi::cast(args[2])->value();
6752
lrn@chromium.org303ada72010-10-27 09:33:13 +00006753 Object* result;
6754 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6755 if (!maybe_result->ToObject(&result)) return maybe_result;
6756 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006757 // Allocate the elements if needed.
6758 if (length > 0) {
6759 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006760 Object* obj;
6761 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6762 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6763 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006764
6765 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006766 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6767 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006768 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006769
6770 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006771 for (int i = 0; i < length; i++) {
6772 array->set(i, *--parameters, mode);
6773 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006774 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006775 }
6776 return result;
6777}
6778
6779
lrn@chromium.org303ada72010-10-27 09:33:13 +00006780static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006781 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006782 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006783 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006784 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006785 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006786
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006787 // Allocate global closures in old space and allocate local closures
6788 // in new space. Additionally pretenure closures that are assigned
6789 // directly to properties.
6790 pretenure = pretenure || (context->global_context() == *context);
6791 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006792 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006793 Factory::NewFunctionFromSharedFunctionInfo(shared,
6794 context,
6795 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796 return *result;
6797}
6798
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006799
lrn@chromium.org303ada72010-10-27 09:33:13 +00006800static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006801 HandleScope scope;
6802 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006803 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006804 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006805
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006806 // Second argument is either null or an array of bound arguments.
6807 FixedArray* bound_args = NULL;
6808 int bound_argc = 0;
6809 if (!args[1]->IsNull()) {
6810 CONVERT_ARG_CHECKED(JSArray, params, 1);
6811 RUNTIME_ASSERT(params->HasFastElements());
6812 bound_args = FixedArray::cast(params->elements());
6813 bound_argc = Smi::cast(params->length())->value();
6814 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006815
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006816 // Find frame containing arguments passed to the caller.
6817 JavaScriptFrameIterator it;
6818 JavaScriptFrame* frame = it.frame();
6819 ASSERT(!frame->is_optimized());
6820 it.AdvanceToArgumentsFrame();
6821 frame = it.frame();
6822 int argc = frame->GetProvidedParametersCount();
6823
6824 // Prepend bound arguments to caller's arguments.
6825 int total_argc = bound_argc + argc;
6826 SmartPointer<Object**> param_data(NewArray<Object**>(total_argc));
6827 for (int i = 0; i < bound_argc; i++) {
6828 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006829 param_data[i] = val.location();
6830 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006831 for (int i = 0; i < argc; i++) {
6832 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
6833 param_data[bound_argc + i] = val.location();
6834 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006835
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006836 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006837 Handle<Object> result =
6838 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006839 if (exception) {
6840 return Failure::Exception();
6841 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006842
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006843 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006844 return *result;
6845}
6846
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006847
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006848static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006849 Handle<Object> prototype = Factory::null_value();
6850 if (function->has_instance_prototype()) {
6851 prototype = Handle<Object>(function->instance_prototype());
6852 }
6853 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006854 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006855 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006856 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006857 function->shared()->set_construct_stub(
6858 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006859 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006860 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006861}
6862
6863
lrn@chromium.org303ada72010-10-27 09:33:13 +00006864static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006865 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006866 ASSERT(args.length() == 1);
6867
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006868 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006869
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006870 // If the constructor isn't a proper function we throw a type error.
6871 if (!constructor->IsJSFunction()) {
6872 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6873 Handle<Object> type_error =
6874 Factory::NewTypeError("not_constructor", arguments);
6875 return Top::Throw(*type_error);
6876 }
6877
6878 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006879
6880 // If function should not have prototype, construction is not allowed. In this
6881 // case generated code bailouts here, since function has no initial_map.
6882 if (!function->should_have_prototype()) {
6883 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6884 Handle<Object> type_error =
6885 Factory::NewTypeError("not_constructor", arguments);
6886 return Top::Throw(*type_error);
6887 }
6888
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006889#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006890 // Handle stepping into constructors if step into is active.
6891 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006892 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006893 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006894#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006895
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006896 if (function->has_initial_map()) {
6897 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006898 // The 'Function' function ignores the receiver object when
6899 // called using 'new' and creates a new JSFunction object that
6900 // is returned. The receiver object is only used for error
6901 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006902 // JSFunction. Factory::NewJSObject() should not be used to
6903 // allocate JSFunctions since it does not properly initialize
6904 // the shared part of the function. Since the receiver is
6905 // ignored anyway, we use the global object as the receiver
6906 // instead of a new JSFunction object. This way, errors are
6907 // reported the same way whether or not 'Function' is called
6908 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006909 return Top::context()->global();
6910 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006911 }
6912
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006913 // The function should be compiled for the optimization hints to be
6914 // available. We cannot use EnsureCompiled because that forces a
6915 // compilation through the shared function info which makes it
6916 // impossible for us to optimize.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006917 Handle<SharedFunctionInfo> shared(function->shared());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006918 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006919
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006920 if (!function->has_initial_map() &&
6921 shared->IsInobjectSlackTrackingInProgress()) {
6922 // The tracking is already in progress for another function. We can only
6923 // track one initial_map at a time, so we force the completion before the
6924 // function is called as a constructor for the first time.
6925 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006926 }
6927
6928 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006929 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006930 // Delay setting the stub if inobject slack tracking is in progress.
6931 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6932 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006933 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006934
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006935 Counters::constructed_objects.Increment();
6936 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006937
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006938 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006939}
6940
6941
lrn@chromium.org303ada72010-10-27 09:33:13 +00006942static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006943 HandleScope scope;
6944 ASSERT(args.length() == 1);
6945
6946 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6947 function->shared()->CompleteInobjectSlackTracking();
6948 TrySettingInlineConstructStub(function);
6949
6950 return Heap::undefined_value();
6951}
6952
6953
lrn@chromium.org303ada72010-10-27 09:33:13 +00006954static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006955 HandleScope scope;
6956 ASSERT(args.length() == 1);
6957
6958 Handle<JSFunction> function = args.at<JSFunction>(0);
6959#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006960 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006961 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006962 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006963 PrintF("]\n");
6964 }
6965#endif
6966
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006967 // Compile the target function. Here we compile using CompileLazyInLoop in
6968 // order to get the optimized version. This helps code like delta-blue
6969 // that calls performance-critical routines through constructors. A
6970 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6971 // direct call. Since the in-loop tracking takes place through CallICs
6972 // this means that things called through constructors are never known to
6973 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006974 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006975 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006976 return Failure::Exception();
6977 }
6978
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006979 // All done. Return the compiled code.
6980 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006981 return function->code();
6982}
6983
6984
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006985static MaybeObject* Runtime_LazyRecompile(Arguments args) {
6986 HandleScope scope;
6987 ASSERT(args.length() == 1);
6988 Handle<JSFunction> function = args.at<JSFunction>(0);
6989 // If the function is not optimizable or debugger is active continue using the
6990 // code from the full compiler.
6991 if (!function->shared()->code()->optimizable() ||
6992 Debug::has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006993 if (FLAG_trace_opt) {
6994 PrintF("[failed to optimize ");
6995 function->PrintName();
6996 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
6997 function->shared()->code()->optimizable() ? "T" : "F",
6998 Debug::has_break_points() ? "T" : "F");
6999 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007000 function->ReplaceCode(function->shared()->code());
7001 return function->code();
7002 }
7003 if (CompileOptimized(function, AstNode::kNoNumber)) {
7004 return function->code();
7005 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007006 if (FLAG_trace_opt) {
7007 PrintF("[failed to optimize ");
7008 function->PrintName();
7009 PrintF(": optimized compilation failed]\n");
7010 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007011 function->ReplaceCode(function->shared()->code());
7012 return Failure::Exception();
7013}
7014
7015
7016static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
7017 HandleScope scope;
7018 ASSERT(args.length() == 1);
7019 RUNTIME_ASSERT(args[0]->IsSmi());
7020 Deoptimizer::BailoutType type =
7021 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
7022 Deoptimizer* deoptimizer = Deoptimizer::Grab();
7023 ASSERT(Heap::IsAllocationAllowed());
7024 int frames = deoptimizer->output_count();
7025
7026 JavaScriptFrameIterator it;
7027 JavaScriptFrame* frame = NULL;
7028 for (int i = 0; i < frames; i++) {
7029 if (i != 0) it.Advance();
7030 frame = it.frame();
7031 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
7032 }
7033 delete deoptimizer;
7034
7035 RUNTIME_ASSERT(frame->function()->IsJSFunction());
7036 Handle<JSFunction> function(JSFunction::cast(frame->function()));
7037 Handle<Object> arguments;
7038 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00007039 if (frame->GetExpression(i) == Heap::arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007040 if (arguments.is_null()) {
7041 // FunctionGetArguments can't throw an exception, so cast away the
7042 // doubt with an assert.
7043 arguments = Handle<Object>(
7044 Accessors::FunctionGetArguments(*function,
7045 NULL)->ToObjectUnchecked());
7046 ASSERT(*arguments != Heap::null_value());
7047 ASSERT(*arguments != Heap::undefined_value());
7048 }
7049 frame->SetExpression(i, *arguments);
7050 }
7051 }
7052
7053 CompilationCache::MarkForLazyOptimizing(function);
7054 if (type == Deoptimizer::EAGER) {
7055 RUNTIME_ASSERT(function->IsOptimized());
7056 } else {
7057 RUNTIME_ASSERT(!function->IsOptimized());
7058 }
7059
7060 // Avoid doing too much work when running with --always-opt and keep
7061 // the optimized code around.
7062 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
7063 return Heap::undefined_value();
7064 }
7065
7066 // Count the number of optimized activations of the function.
7067 int activations = 0;
7068 while (!it.done()) {
7069 JavaScriptFrame* frame = it.frame();
7070 if (frame->is_optimized() && frame->function() == *function) {
7071 activations++;
7072 }
7073 it.Advance();
7074 }
7075
7076 // TODO(kasperl): For now, we cannot support removing the optimized
7077 // code when we have recursive invocations of the same function.
7078 if (activations == 0) {
7079 if (FLAG_trace_deopt) {
7080 PrintF("[removing optimized code for: ");
7081 function->PrintName();
7082 PrintF("]\n");
7083 }
7084 function->ReplaceCode(function->shared()->code());
7085 }
7086 return Heap::undefined_value();
7087}
7088
7089
7090static MaybeObject* Runtime_NotifyOSR(Arguments args) {
7091 Deoptimizer* deoptimizer = Deoptimizer::Grab();
7092 delete deoptimizer;
7093 return Heap::undefined_value();
7094}
7095
7096
7097static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
7098 HandleScope scope;
7099 ASSERT(args.length() == 1);
7100 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7101 if (!function->IsOptimized()) return Heap::undefined_value();
7102
7103 Deoptimizer::DeoptimizeFunction(*function);
7104
7105 return Heap::undefined_value();
7106}
7107
7108
7109static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
7110 HandleScope scope;
7111 ASSERT(args.length() == 1);
7112 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7113
7114 // We're not prepared to handle a function with arguments object.
7115 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7116
7117 // We have hit a back edge in an unoptimized frame for a function that was
7118 // selected for on-stack replacement. Find the unoptimized code object.
7119 Handle<Code> unoptimized(function->shared()->code());
7120 // Keep track of whether we've succeeded in optimizing.
7121 bool succeeded = unoptimized->optimizable();
7122 if (succeeded) {
7123 // If we are trying to do OSR when there are already optimized
7124 // activations of the function, it means (a) the function is directly or
7125 // indirectly recursive and (b) an optimized invocation has been
7126 // deoptimized so that we are currently in an unoptimized activation.
7127 // Check for optimized activations of this function.
7128 JavaScriptFrameIterator it;
7129 while (succeeded && !it.done()) {
7130 JavaScriptFrame* frame = it.frame();
7131 succeeded = !frame->is_optimized() || frame->function() != *function;
7132 it.Advance();
7133 }
7134 }
7135
7136 int ast_id = AstNode::kNoNumber;
7137 if (succeeded) {
7138 // The top JS function is this one, the PC is somewhere in the
7139 // unoptimized code.
7140 JavaScriptFrameIterator it;
7141 JavaScriptFrame* frame = it.frame();
7142 ASSERT(frame->function() == *function);
7143 ASSERT(frame->code() == *unoptimized);
7144 ASSERT(unoptimized->contains(frame->pc()));
7145
7146 // Use linear search of the unoptimized code's stack check table to find
7147 // the AST id matching the PC.
7148 Address start = unoptimized->instruction_start();
7149 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007150 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007151 uint32_t table_length = Memory::uint32_at(table_cursor);
7152 table_cursor += kIntSize;
7153 for (unsigned i = 0; i < table_length; ++i) {
7154 // Table entries are (AST id, pc offset) pairs.
7155 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7156 if (pc_offset == target_pc_offset) {
7157 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7158 break;
7159 }
7160 table_cursor += 2 * kIntSize;
7161 }
7162 ASSERT(ast_id != AstNode::kNoNumber);
7163 if (FLAG_trace_osr) {
7164 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7165 function->PrintName();
7166 PrintF("]\n");
7167 }
7168
7169 // Try to compile the optimized code. A true return value from
7170 // CompileOptimized means that compilation succeeded, not necessarily
7171 // that optimization succeeded.
7172 if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
7173 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7174 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007175 if (data->OsrPcOffset()->value() >= 0) {
7176 if (FLAG_trace_osr) {
7177 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007178 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007179 }
7180 ASSERT(data->OsrAstId()->value() == ast_id);
7181 } else {
7182 // We may never generate the desired OSR entry if we emit an
7183 // early deoptimize.
7184 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007185 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007186 } else {
7187 succeeded = false;
7188 }
7189 }
7190
7191 // Revert to the original stack checks in the original unoptimized code.
7192 if (FLAG_trace_osr) {
7193 PrintF("[restoring original stack checks in ");
7194 function->PrintName();
7195 PrintF("]\n");
7196 }
7197 StackCheckStub check_stub;
7198 Handle<Code> check_code = check_stub.GetCode();
7199 Handle<Code> replacement_code(
7200 Builtins::builtin(Builtins::OnStackReplacement));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007201 Deoptimizer::RevertStackCheckCode(*unoptimized,
7202 *check_code,
7203 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007204
7205 // Allow OSR only at nesting level zero again.
7206 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7207
7208 // If the optimization attempt succeeded, return the AST id tagged as a
7209 // smi. This tells the builtin that we need to translate the unoptimized
7210 // frame to an optimized one.
7211 if (succeeded) {
7212 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7213 return Smi::FromInt(ast_id);
7214 } else {
7215 return Smi::FromInt(-1);
7216 }
7217}
7218
7219
lrn@chromium.org303ada72010-10-27 09:33:13 +00007220static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007221 HandleScope scope;
7222 ASSERT(args.length() == 1);
7223 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7224 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7225}
7226
7227
lrn@chromium.org303ada72010-10-27 09:33:13 +00007228static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007229 HandleScope scope;
7230 ASSERT(args.length() == 1);
7231 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7232 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7233}
7234
7235
lrn@chromium.org303ada72010-10-27 09:33:13 +00007236static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007237 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007238 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007239
kasper.lund7276f142008-07-30 08:49:36 +00007240 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007241 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007242 Object* result;
7243 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
7244 if (!maybe_result->ToObject(&result)) return maybe_result;
7245 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007246
7247 Top::set_context(Context::cast(result));
7248
kasper.lund7276f142008-07-30 08:49:36 +00007249 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007250}
7251
lrn@chromium.org303ada72010-10-27 09:33:13 +00007252
7253MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
7254 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007255 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007256 Object* js_object = object;
7257 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007258 MaybeObject* maybe_js_object = js_object->ToObject();
7259 if (!maybe_js_object->ToObject(&js_object)) {
7260 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7261 return maybe_js_object;
7262 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007263 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007264 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007265 Handle<Object> result =
7266 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
7267 return Top::Throw(*result);
7268 }
7269 }
7270
lrn@chromium.org303ada72010-10-27 09:33:13 +00007271 Object* result;
7272 { MaybeObject* maybe_result =
7273 Heap::AllocateWithContext(Top::context(),
7274 JSObject::cast(js_object),
7275 is_catch_context);
7276 if (!maybe_result->ToObject(&result)) return maybe_result;
7277 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007278
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007279 Context* context = Context::cast(result);
7280 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007281
kasper.lund7276f142008-07-30 08:49:36 +00007282 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007283}
7284
7285
lrn@chromium.org303ada72010-10-27 09:33:13 +00007286static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007287 NoHandleAllocation ha;
7288 ASSERT(args.length() == 1);
7289 return PushContextHelper(args[0], false);
7290}
7291
7292
lrn@chromium.org303ada72010-10-27 09:33:13 +00007293static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007294 NoHandleAllocation ha;
7295 ASSERT(args.length() == 1);
7296 return PushContextHelper(args[0], true);
7297}
7298
7299
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007300static MaybeObject* Runtime_DeleteContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007301 HandleScope scope;
7302 ASSERT(args.length() == 2);
7303
7304 CONVERT_ARG_CHECKED(Context, context, 0);
7305 CONVERT_ARG_CHECKED(String, name, 1);
7306
7307 int index;
7308 PropertyAttributes attributes;
7309 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007310 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007312 // If the slot was not found the result is true.
7313 if (holder.is_null()) {
7314 return Heap::true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007315 }
7316
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007317 // If the slot was found in a context, it should be DONT_DELETE.
7318 if (holder->IsContext()) {
7319 return Heap::false_value();
7320 }
7321
7322 // The slot was found in a JSObject, either a context extension object,
7323 // the global object, or an arguments object. Try to delete it
7324 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7325 // which allows deleting all parameters in functions that mention
7326 // 'arguments', we do this even for the case of slots found on an
7327 // arguments object. The slot was found on an arguments object if the
7328 // index is non-negative.
7329 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7330 if (index >= 0) {
7331 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7332 } else {
7333 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7334 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007335}
7336
7337
ager@chromium.orga1645e22009-09-09 19:27:10 +00007338// A mechanism to return a pair of Object pointers in registers (if possible).
7339// How this is achieved is calling convention-dependent.
7340// All currently supported x86 compiles uses calling conventions that are cdecl
7341// variants where a 64-bit value is returned in two 32-bit registers
7342// (edx:eax on ia32, r1:r0 on ARM).
7343// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7344// In Win64 calling convention, a struct of two pointers is returned in memory,
7345// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007346#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007347struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007348 MaybeObject* x;
7349 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007350};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007351
lrn@chromium.org303ada72010-10-27 09:33:13 +00007352static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007353 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007354 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7355 // In Win64 they are assigned to a hidden first argument.
7356 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007357}
7358#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007359typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007360static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007361 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007362 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007363}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007364#endif
7365
7366
lrn@chromium.org303ada72010-10-27 09:33:13 +00007367static inline MaybeObject* Unhole(MaybeObject* x,
7368 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007369 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7370 USE(attributes);
7371 return x->IsTheHole() ? Heap::undefined_value() : x;
7372}
7373
7374
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007375static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7376 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007377 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007378 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007379 JSFunction* context_extension_function =
7380 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007381 // If the holder isn't a context extension object, we just return it
7382 // as the receiver. This allows arguments objects to be used as
7383 // receivers, but only if they are put in the context scope chain
7384 // explicitly via a with-statement.
7385 Object* constructor = holder->map()->constructor();
7386 if (constructor != context_extension_function) return holder;
7387 // Fall back to using the global object as the receiver if the
7388 // property turns out to be a local variable allocated in a context
7389 // extension object - introduced via eval.
7390 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007391}
7392
7393
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007394static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007395 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00007396 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007398 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00007399 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007400 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007401 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007402 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007403
7404 int index;
7405 PropertyAttributes attributes;
7406 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007407 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007408
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007409 // If the index is non-negative, the slot has been found in a local
7410 // variable or a parameter. Read it from the context object or the
7411 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007412 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007413 // If the "property" we were looking for is a local variable or an
7414 // argument in a context, the receiver is the global object; see
7415 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7416 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007417 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007418 ? Context::cast(*holder)->get(index)
7419 : JSObject::cast(*holder)->GetElement(index);
7420 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007421 }
7422
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007423 // If the holder is found, we read the property from it.
7424 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007425 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007426 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007427 JSObject* receiver;
7428 if (object->IsGlobalObject()) {
7429 receiver = GlobalObject::cast(object)->global_receiver();
7430 } else if (context->is_exception_holder(*holder)) {
7431 receiver = Top::context()->global()->global_receiver();
7432 } else {
7433 receiver = ComputeReceiverForNonGlobal(object);
7434 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007435 // No need to unhole the value here. This is taken care of by the
7436 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007437 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007438 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007439 }
7440
7441 if (throw_error) {
7442 // The property doesn't exist - throw exception.
7443 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007444 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007445 return MakePair(Top::Throw(*reference_error), NULL);
7446 } else {
7447 // The property doesn't exist - return undefined
7448 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7449 }
7450}
7451
7452
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007453static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007454 return LoadContextSlotHelper(args, true);
7455}
7456
7457
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007458static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007459 return LoadContextSlotHelper(args, false);
7460}
7461
7462
lrn@chromium.org303ada72010-10-27 09:33:13 +00007463static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007464 HandleScope scope;
7465 ASSERT(args.length() == 3);
7466
7467 Handle<Object> value(args[0]);
7468 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007469 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007470
7471 int index;
7472 PropertyAttributes attributes;
7473 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007474 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007475
7476 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007477 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007478 // Ignore if read_only variable.
7479 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007480 // Context is a fixed array and set cannot fail.
7481 Context::cast(*holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007482 }
7483 } else {
7484 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007485 Handle<Object> result =
7486 SetElement(Handle<JSObject>::cast(holder), index, value);
7487 if (result.is_null()) {
7488 ASSERT(Top::has_pending_exception());
7489 return Failure::Exception();
7490 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007491 }
7492 return *value;
7493 }
7494
7495 // Slow case: The property is not in a FixedArray context.
7496 // It is either in an JSObject extension context or it was not found.
7497 Handle<JSObject> context_ext;
7498
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007499 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007500 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007501 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007502 } else {
7503 // The property was not found. It needs to be stored in the global context.
7504 ASSERT(attributes == ABSENT);
7505 attributes = NONE;
7506 context_ext = Handle<JSObject>(Top::context()->global());
7507 }
7508
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007509 // Set the property, but ignore if read_only variable on the context
7510 // extension object itself.
7511 if ((attributes & READ_ONLY) == 0 ||
7512 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007513 RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, NONE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007514 }
7515 return *value;
7516}
7517
7518
lrn@chromium.org303ada72010-10-27 09:33:13 +00007519static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007520 HandleScope scope;
7521 ASSERT(args.length() == 1);
7522
7523 return Top::Throw(args[0]);
7524}
7525
7526
lrn@chromium.org303ada72010-10-27 09:33:13 +00007527static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007528 HandleScope scope;
7529 ASSERT(args.length() == 1);
7530
7531 return Top::ReThrow(args[0]);
7532}
7533
7534
lrn@chromium.org303ada72010-10-27 09:33:13 +00007535static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007536 ASSERT_EQ(0, args.length());
7537 return Top::PromoteScheduledException();
7538}
7539
7540
lrn@chromium.org303ada72010-10-27 09:33:13 +00007541static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007542 HandleScope scope;
7543 ASSERT(args.length() == 1);
7544
7545 Handle<Object> name(args[0]);
7546 Handle<Object> reference_error =
7547 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7548 return Top::Throw(*reference_error);
7549}
7550
7551
lrn@chromium.org303ada72010-10-27 09:33:13 +00007552static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007553 NoHandleAllocation na;
7554 return Top::StackOverflow();
7555}
7556
7557
lrn@chromium.org303ada72010-10-27 09:33:13 +00007558static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007559 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007560
7561 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007562 if (StackGuard::IsStackOverflow()) {
7563 return Runtime_StackOverflow(args);
7564 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007565
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007566 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007567}
7568
7569
7570// NOTE: These PrintXXX functions are defined for all builds (not just
7571// DEBUG builds) because we may want to be able to trace function
7572// calls in all modes.
7573static void PrintString(String* str) {
7574 // not uncommon to have empty strings
7575 if (str->length() > 0) {
7576 SmartPointer<char> s =
7577 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7578 PrintF("%s", *s);
7579 }
7580}
7581
7582
7583static void PrintObject(Object* obj) {
7584 if (obj->IsSmi()) {
7585 PrintF("%d", Smi::cast(obj)->value());
7586 } else if (obj->IsString() || obj->IsSymbol()) {
7587 PrintString(String::cast(obj));
7588 } else if (obj->IsNumber()) {
7589 PrintF("%g", obj->Number());
7590 } else if (obj->IsFailure()) {
7591 PrintF("<failure>");
7592 } else if (obj->IsUndefined()) {
7593 PrintF("<undefined>");
7594 } else if (obj->IsNull()) {
7595 PrintF("<null>");
7596 } else if (obj->IsTrue()) {
7597 PrintF("<true>");
7598 } else if (obj->IsFalse()) {
7599 PrintF("<false>");
7600 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007601 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007602 }
7603}
7604
7605
7606static int StackSize() {
7607 int n = 0;
7608 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7609 return n;
7610}
7611
7612
7613static void PrintTransition(Object* result) {
7614 // indentation
7615 { const int nmax = 80;
7616 int n = StackSize();
7617 if (n <= nmax)
7618 PrintF("%4d:%*s", n, n, "");
7619 else
7620 PrintF("%4d:%*s", n, nmax, "...");
7621 }
7622
7623 if (result == NULL) {
7624 // constructor calls
7625 JavaScriptFrameIterator it;
7626 JavaScriptFrame* frame = it.frame();
7627 if (frame->IsConstructor()) PrintF("new ");
7628 // function name
7629 Object* fun = frame->function();
7630 if (fun->IsJSFunction()) {
7631 PrintObject(JSFunction::cast(fun)->shared()->name());
7632 } else {
7633 PrintObject(fun);
7634 }
7635 // function arguments
7636 // (we are intentionally only printing the actually
7637 // supplied parameters, not all parameters required)
7638 PrintF("(this=");
7639 PrintObject(frame->receiver());
7640 const int length = frame->GetProvidedParametersCount();
7641 for (int i = 0; i < length; i++) {
7642 PrintF(", ");
7643 PrintObject(frame->GetParameter(i));
7644 }
7645 PrintF(") {\n");
7646
7647 } else {
7648 // function result
7649 PrintF("} -> ");
7650 PrintObject(result);
7651 PrintF("\n");
7652 }
7653}
7654
7655
lrn@chromium.org303ada72010-10-27 09:33:13 +00007656static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007657 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007658 NoHandleAllocation ha;
7659 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007660 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007661}
7662
7663
lrn@chromium.org303ada72010-10-27 09:33:13 +00007664static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007665 NoHandleAllocation ha;
7666 PrintTransition(args[0]);
7667 return args[0]; // return TOS
7668}
7669
7670
lrn@chromium.org303ada72010-10-27 09:33:13 +00007671static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007672 NoHandleAllocation ha;
7673 ASSERT(args.length() == 1);
7674
7675#ifdef DEBUG
7676 if (args[0]->IsString()) {
7677 // If we have a string, assume it's a code "marker"
7678 // and print some interesting cpu debugging info.
7679 JavaScriptFrameIterator it;
7680 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007681 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7682 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007683 } else {
7684 PrintF("DebugPrint: ");
7685 }
7686 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007687 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007688 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007689 HeapObject::cast(args[0])->map()->Print();
7690 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007691#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007692 // ShortPrint is available in release mode. Print is not.
7693 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007694#endif
7695 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007696 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007697
7698 return args[0]; // return TOS
7699}
7700
7701
lrn@chromium.org303ada72010-10-27 09:33:13 +00007702static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007703 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007704 NoHandleAllocation ha;
7705 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007706 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007707}
7708
7709
lrn@chromium.org303ada72010-10-27 09:33:13 +00007710static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007711 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007712 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007713
7714 // According to ECMA-262, section 15.9.1, page 117, the precision of
7715 // the number in a Date object representing a particular instant in
7716 // time is milliseconds. Therefore, we floor the result of getting
7717 // the OS time.
7718 double millis = floor(OS::TimeCurrentMillis());
7719 return Heap::NumberFromDouble(millis);
7720}
7721
7722
lrn@chromium.org303ada72010-10-27 09:33:13 +00007723static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007724 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007725 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007726
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007727 CONVERT_ARG_CHECKED(String, str, 0);
7728 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007729
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007730 CONVERT_ARG_CHECKED(JSArray, output, 1);
7731 RUNTIME_ASSERT(output->HasFastElements());
7732
7733 AssertNoAllocation no_allocation;
7734
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007735 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007736 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7737 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007738 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007739 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007740 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007741 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007742 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7743 }
7744
7745 if (result) {
7746 return *output;
7747 } else {
7748 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007749 }
7750}
7751
7752
lrn@chromium.org303ada72010-10-27 09:33:13 +00007753static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007754 NoHandleAllocation ha;
7755 ASSERT(args.length() == 1);
7756
7757 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007758 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007759 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7760}
7761
7762
lrn@chromium.org303ada72010-10-27 09:33:13 +00007763static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007764 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007765 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007766
7767 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7768}
7769
7770
lrn@chromium.org303ada72010-10-27 09:33:13 +00007771static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007772 NoHandleAllocation ha;
7773 ASSERT(args.length() == 1);
7774
7775 CONVERT_DOUBLE_CHECKED(x, args[0]);
7776 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7777}
7778
7779
lrn@chromium.org303ada72010-10-27 09:33:13 +00007780static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007781 ASSERT(args.length() == 1);
7782 Object* global = args[0];
7783 if (!global->IsJSGlobalObject()) return Heap::null_value();
7784 return JSGlobalObject::cast(global)->global_receiver();
7785}
7786
7787
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007788static MaybeObject* Runtime_ParseJson(Arguments args) {
7789 HandleScope scope;
7790 ASSERT_EQ(1, args.length());
7791 CONVERT_ARG_CHECKED(String, source, 0);
7792
7793 Handle<Object> result = JsonParser::Parse(source);
7794 if (result.is_null()) {
7795 // Syntax error or stack overflow in scanner.
7796 ASSERT(Top::has_pending_exception());
7797 return Failure::Exception();
7798 }
7799 return *result;
7800}
7801
7802
lrn@chromium.org303ada72010-10-27 09:33:13 +00007803static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007804 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007805 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007806 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007807
ager@chromium.org381abbb2009-02-25 13:23:22 +00007808 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007809 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007810 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7811 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007812 true,
7813 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007814 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007815 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007816 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007817 return *fun;
7818}
7819
7820
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007821static ObjectPair CompileGlobalEval(Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007822 Handle<Object> receiver,
7823 StrictModeFlag mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007824 // Deal with a normal eval call with a string argument. Compile it
7825 // and return the compiled function bound in the local context.
7826 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7827 source,
7828 Handle<Context>(Top::context()),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007829 Top::context()->IsGlobalContext(),
7830 mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007831 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7832 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7833 shared,
7834 Handle<Context>(Top::context()),
7835 NOT_TENURED);
7836 return MakePair(*compiled, *receiver);
7837}
7838
7839
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007840static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007841 ASSERT(args.length() == 4);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007842 if (!args[0]->IsJSFunction()) {
7843 return MakePair(Top::ThrowIllegalOperation(), NULL);
7844 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007845
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007846 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007847 Handle<JSFunction> callee = args.at<JSFunction>(0);
7848 Handle<Object> receiver; // Will be overwritten.
7849
7850 // Compute the calling context.
7851 Handle<Context> context = Handle<Context>(Top::context());
7852#ifdef DEBUG
7853 // Make sure Top::context() agrees with the old code that traversed
7854 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007855 StackFrameLocator locator;
7856 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007857 ASSERT(Context::cast(frame->context()) == *context);
7858#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007859
7860 // Find where the 'eval' symbol is bound. It is unaliased only if
7861 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007862 int index = -1;
7863 PropertyAttributes attributes = ABSENT;
7864 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007865 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7866 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007867 // Stop search when eval is found or when the global context is
7868 // reached.
7869 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007870 if (context->is_function_context()) {
7871 context = Handle<Context>(Context::cast(context->closure()->context()));
7872 } else {
7873 context = Handle<Context>(context->previous());
7874 }
7875 }
7876
iposva@chromium.org245aa852009-02-10 00:49:54 +00007877 // If eval could not be resolved, it has been deleted and we need to
7878 // throw a reference error.
7879 if (attributes == ABSENT) {
7880 Handle<Object> name = Factory::eval_symbol();
7881 Handle<Object> reference_error =
7882 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007883 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007884 }
7885
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007886 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007887 // 'eval' is not bound in the global context. Just call the function
7888 // with the given arguments. This is not necessarily the global eval.
7889 if (receiver->IsContext()) {
7890 context = Handle<Context>::cast(receiver);
7891 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007892 } else if (receiver->IsJSContextExtensionObject()) {
7893 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007894 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007895 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007896 }
7897
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007898 // 'eval' is bound in the global context, but it may have been overwritten.
7899 // Compare it to the builtin 'GlobalEval' function to make sure.
7900 if (*callee != Top::global_context()->global_eval_fun() ||
7901 !args[1]->IsString()) {
7902 return MakePair(*callee, Top::context()->global()->global_receiver());
7903 }
7904
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007905 ASSERT(args[3]->IsSmi());
7906 return CompileGlobalEval(args.at<String>(1),
7907 args.at<Object>(2),
7908 static_cast<StrictModeFlag>(
7909 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007910}
7911
7912
7913static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007914 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007915 if (!args[0]->IsJSFunction()) {
7916 return MakePair(Top::ThrowIllegalOperation(), NULL);
7917 }
7918
7919 HandleScope scope;
7920 Handle<JSFunction> callee = args.at<JSFunction>(0);
7921
7922 // 'eval' is bound in the global context, but it may have been overwritten.
7923 // Compare it to the builtin 'GlobalEval' function to make sure.
7924 if (*callee != Top::global_context()->global_eval_fun() ||
7925 !args[1]->IsString()) {
7926 return MakePair(*callee, Top::context()->global()->global_receiver());
7927 }
7928
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007929 ASSERT(args[3]->IsSmi());
7930 return CompileGlobalEval(args.at<String>(1),
7931 args.at<Object>(2),
7932 static_cast<StrictModeFlag>(
7933 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007934}
7935
7936
lrn@chromium.org303ada72010-10-27 09:33:13 +00007937static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007938 // This utility adjusts the property attributes for newly created Function
7939 // object ("new Function(...)") by changing the map.
7940 // All it does is changing the prototype property to enumerable
7941 // as specified in ECMA262, 15.3.5.2.
7942 HandleScope scope;
7943 ASSERT(args.length() == 1);
7944 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7945 ASSERT(func->map()->instance_type() ==
7946 Top::function_instance_map()->instance_type());
7947 ASSERT(func->map()->instance_size() ==
7948 Top::function_instance_map()->instance_size());
7949 func->set_map(*Top::function_instance_map());
7950 return *func;
7951}
7952
7953
lrn@chromium.org303ada72010-10-27 09:33:13 +00007954static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007955 // Allocate a block of memory in NewSpace (filled with a filler).
7956 // Use as fallback for allocation in generated code when NewSpace
7957 // is full.
7958 ASSERT(args.length() == 1);
7959 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7960 int size = size_smi->value();
7961 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7962 RUNTIME_ASSERT(size > 0);
7963 static const int kMinFreeNewSpaceAfterGC =
7964 Heap::InitialSemiSpaceSize() * 3/4;
7965 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007966 Object* allocation;
7967 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7968 if (maybe_allocation->ToObject(&allocation)) {
7969 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7970 }
7971 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007972 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007973}
7974
7975
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007976// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007977// array. Returns true if the element was pushed on the stack and
7978// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007979static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007980 ASSERT(args.length() == 2);
7981 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007982 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007983 RUNTIME_ASSERT(array->HasFastElements());
7984 int length = Smi::cast(array->length())->value();
7985 FixedArray* elements = FixedArray::cast(array->elements());
7986 for (int i = 0; i < length; i++) {
7987 if (elements->get(i) == element) return Heap::false_value();
7988 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007989 Object* obj;
7990 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
7991 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7992 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007993 return Heap::true_value();
7994}
7995
7996
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007997/**
7998 * A simple visitor visits every element of Array's.
7999 * The backend storage can be a fixed array for fast elements case,
8000 * or a dictionary for sparse array. Since Dictionary is a subtype
8001 * of FixedArray, the class can be used by both fast and slow cases.
8002 * The second parameter of the constructor, fast_elements, specifies
8003 * whether the storage is a FixedArray or Dictionary.
8004 *
8005 * An index limit is used to deal with the situation that a result array
8006 * length overflows 32-bit non-negative integer.
8007 */
8008class ArrayConcatVisitor {
8009 public:
8010 ArrayConcatVisitor(Handle<FixedArray> storage,
8011 uint32_t index_limit,
8012 bool fast_elements) :
8013 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008014 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008015
8016 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008017 if (i >= index_limit_ - index_offset_) return;
8018 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008019
8020 if (fast_elements_) {
8021 ASSERT(index < static_cast<uint32_t>(storage_->length()));
8022 storage_->set(index, *elm);
8023
8024 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008025 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
8026 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008027 Factory::DictionaryAtNumberPut(dict, index, elm);
8028 if (!result.is_identical_to(dict))
8029 storage_ = result;
8030 }
8031 }
8032
8033 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008034 if (index_limit_ - index_offset_ < delta) {
8035 index_offset_ = index_limit_;
8036 } else {
8037 index_offset_ += delta;
8038 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008039 }
8040
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008041 Handle<FixedArray> storage() { return storage_; }
8042
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008043 private:
8044 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008045 // Limit on the accepted indices. Elements with indices larger than the
8046 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008047 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008048 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008049 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008050 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008051};
8052
8053
ager@chromium.org3811b432009-10-28 14:53:37 +00008054template<class ExternalArrayClass, class ElementType>
8055static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
8056 bool elements_are_ints,
8057 bool elements_are_guaranteed_smis,
8058 uint32_t range,
8059 ArrayConcatVisitor* visitor) {
8060 Handle<ExternalArrayClass> array(
8061 ExternalArrayClass::cast(receiver->elements()));
8062 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
8063
8064 if (visitor != NULL) {
8065 if (elements_are_ints) {
8066 if (elements_are_guaranteed_smis) {
8067 for (uint32_t j = 0; j < len; j++) {
8068 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8069 visitor->visit(j, e);
8070 }
8071 } else {
8072 for (uint32_t j = 0; j < len; j++) {
8073 int64_t val = static_cast<int64_t>(array->get(j));
8074 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8075 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8076 visitor->visit(j, e);
8077 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008078 Handle<Object> e =
8079 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00008080 visitor->visit(j, e);
8081 }
8082 }
8083 }
8084 } else {
8085 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008086 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00008087 visitor->visit(j, e);
8088 }
8089 }
8090 }
8091
8092 return len;
8093}
8094
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008095/**
8096 * A helper function that visits elements of a JSObject. Only elements
8097 * whose index between 0 and range (exclusive) are visited.
8098 *
8099 * If the third parameter, visitor, is not NULL, the visitor is called
8100 * with parameters, 'visitor_index_offset + element index' and the element.
8101 *
8102 * It returns the number of visisted elements.
8103 */
8104static uint32_t IterateElements(Handle<JSObject> receiver,
8105 uint32_t range,
8106 ArrayConcatVisitor* visitor) {
8107 uint32_t num_of_elements = 0;
8108
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008109 switch (receiver->GetElementsKind()) {
8110 case JSObject::FAST_ELEMENTS: {
8111 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8112 uint32_t len = elements->length();
8113 if (range < len) {
8114 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008115 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008116
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008117 for (uint32_t j = 0; j < len; j++) {
8118 Handle<Object> e(elements->get(j));
8119 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008120 num_of_elements++;
8121 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008122 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008123 }
8124 }
8125 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008126 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008127 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008128 case JSObject::PIXEL_ELEMENTS: {
8129 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
8130 uint32_t len = pixels->length();
8131 if (range < len) {
8132 len = range;
8133 }
8134
8135 for (uint32_t j = 0; j < len; j++) {
8136 num_of_elements++;
8137 if (visitor != NULL) {
8138 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8139 visitor->visit(j, e);
8140 }
8141 }
8142 break;
8143 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008144 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8145 num_of_elements =
8146 IterateExternalArrayElements<ExternalByteArray, int8_t>(
8147 receiver, true, true, range, visitor);
8148 break;
8149 }
8150 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8151 num_of_elements =
8152 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
8153 receiver, true, true, range, visitor);
8154 break;
8155 }
8156 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8157 num_of_elements =
8158 IterateExternalArrayElements<ExternalShortArray, int16_t>(
8159 receiver, true, true, range, visitor);
8160 break;
8161 }
8162 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8163 num_of_elements =
8164 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
8165 receiver, true, true, range, visitor);
8166 break;
8167 }
8168 case JSObject::EXTERNAL_INT_ELEMENTS: {
8169 num_of_elements =
8170 IterateExternalArrayElements<ExternalIntArray, int32_t>(
8171 receiver, true, false, range, visitor);
8172 break;
8173 }
8174 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8175 num_of_elements =
8176 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
8177 receiver, true, false, range, visitor);
8178 break;
8179 }
8180 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8181 num_of_elements =
8182 IterateExternalArrayElements<ExternalFloatArray, float>(
8183 receiver, false, false, range, visitor);
8184 break;
8185 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008186 case JSObject::DICTIONARY_ELEMENTS: {
8187 Handle<NumberDictionary> dict(receiver->element_dictionary());
8188 uint32_t capacity = dict->Capacity();
8189 for (uint32_t j = 0; j < capacity; j++) {
8190 Handle<Object> k(dict->KeyAt(j));
8191 if (dict->IsKey(*k)) {
8192 ASSERT(k->IsNumber());
8193 uint32_t index = static_cast<uint32_t>(k->Number());
8194 if (index < range) {
8195 num_of_elements++;
8196 if (visitor) {
8197 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
8198 }
8199 }
8200 }
8201 }
8202 break;
8203 }
8204 default:
8205 UNREACHABLE();
8206 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008207 }
8208
8209 return num_of_elements;
8210}
8211
8212
8213/**
8214 * A helper function that visits elements of an Array object, and elements
8215 * on its prototypes.
8216 *
8217 * Elements on prototypes are visited first, and only elements whose indices
8218 * less than Array length are visited.
8219 *
8220 * If a ArrayConcatVisitor object is given, the visitor is called with
8221 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008222 *
8223 * The returned number of elements is an upper bound on the actual number
8224 * of elements added. If the same element occurs in more than one object
8225 * in the array's prototype chain, it will be counted more than once, but
8226 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008227 */
8228static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
8229 ArrayConcatVisitor* visitor) {
8230 uint32_t range = static_cast<uint32_t>(array->length()->Number());
8231 Handle<Object> obj = array;
8232
8233 static const int kEstimatedPrototypes = 3;
8234 List< Handle<JSObject> > objects(kEstimatedPrototypes);
8235
8236 // Visit prototype first. If an element on the prototype is shadowed by
8237 // the inheritor using the same index, the ArrayConcatVisitor visits
8238 // the prototype element before the shadowing element.
8239 // The visitor can simply overwrite the old value by new value using
8240 // the same index. This follows Array::concat semantics.
8241 while (!obj->IsNull()) {
8242 objects.Add(Handle<JSObject>::cast(obj));
8243 obj = Handle<Object>(obj->GetPrototype());
8244 }
8245
8246 uint32_t nof_elements = 0;
8247 for (int i = objects.length() - 1; i >= 0; i--) {
8248 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008249 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008250 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008251
8252 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
8253 nof_elements = JSObject::kMaxElementCount;
8254 } else {
8255 nof_elements += encountered_elements;
8256 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008257 }
8258
8259 return nof_elements;
8260}
8261
8262
8263/**
8264 * A helper function of Runtime_ArrayConcat.
8265 *
8266 * The first argument is an Array of arrays and objects. It is the
8267 * same as the arguments array of Array::concat JS function.
8268 *
8269 * If an argument is an Array object, the function visits array
8270 * elements. If an argument is not an Array object, the function
8271 * visits the object as if it is an one-element array.
8272 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008273 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008274 * non-negative number is used as new length. For example, if one
8275 * array length is 2^32 - 1, second array length is 1, the
8276 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008277 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
8278 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008279 */
8280static uint32_t IterateArguments(Handle<JSArray> arguments,
8281 ArrayConcatVisitor* visitor) {
8282 uint32_t visited_elements = 0;
8283 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8284
8285 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008286 Object *element;
8287 MaybeObject* maybe_element = arguments->GetElement(i);
8288 // This if() is not expected to fail, but we have the check in the
8289 // interest of hardening the runtime calls.
8290 if (maybe_element->ToObject(&element)) {
8291 Handle<Object> obj(element);
8292 if (obj->IsJSArray()) {
8293 Handle<JSArray> array = Handle<JSArray>::cast(obj);
8294 uint32_t len = static_cast<uint32_t>(array->length()->Number());
8295 uint32_t nof_elements =
8296 IterateArrayAndPrototypeElements(array, visitor);
8297 // Total elements of array and its prototype chain can be more than
8298 // the array length, but ArrayConcat can only concatenate at most
8299 // the array length number of elements. We use the length as an estimate
8300 // for the actual number of elements added.
8301 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
8302 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
8303 visited_elements = JSArray::kMaxElementCount;
8304 } else {
8305 visited_elements += added_elements;
8306 }
8307 if (visitor) visitor->increase_index_offset(len);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008308 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008309 if (visitor) {
8310 visitor->visit(0, obj);
8311 visitor->increase_index_offset(1);
8312 }
8313 if (visited_elements < JSArray::kMaxElementCount) {
8314 visited_elements++;
8315 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008316 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008317 }
8318 }
8319 return visited_elements;
8320}
8321
8322
8323/**
8324 * Array::concat implementation.
8325 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008326 * TODO(lrn): Fix non-compliance for very large concatenations and update to
8327 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008328 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008329static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008330 ASSERT(args.length() == 1);
8331 HandleScope handle_scope;
8332
8333 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
8334 Handle<JSArray> arguments(arg_arrays);
8335
8336 // Pass 1: estimate the number of elements of the result
8337 // (it could be more than real numbers if prototype has elements).
8338 uint32_t result_length = 0;
8339 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8340
8341 { AssertNoAllocation nogc;
8342 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008343 Object* obj;
8344 MaybeObject* maybe_object = arguments->GetElement(i);
8345 // This if() is not expected to fail, but we have the check in the
8346 // interest of hardening the runtime calls.
8347 if (maybe_object->ToObject(&obj)) {
8348 uint32_t length_estimate;
8349 if (obj->IsJSArray()) {
8350 length_estimate =
8351 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
8352 } else {
8353 length_estimate = 1;
8354 }
8355 if (JSObject::kMaxElementCount - result_length < length_estimate) {
8356 result_length = JSObject::kMaxElementCount;
8357 break;
8358 }
8359 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008360 }
8361 }
8362 }
8363
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008364 // Allocate an empty array, will set map, length, and content later.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008365 Handle<JSArray> result = Factory::NewJSArray(0);
8366
8367 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
8368 // If estimated number of elements is more than half of length, a
8369 // fixed array (fast case) is more time and space-efficient than a
8370 // dictionary.
8371 bool fast_case = (estimate_nof_elements * 2) >= result_length;
8372
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008373 Handle<Map> map;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008374 Handle<FixedArray> storage;
8375 if (fast_case) {
8376 // The backing storage array must have non-existing elements to
8377 // preserve holes across concat operations.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008378 map = Factory::GetFastElementsMap(Handle<Map>(result->map()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008379 storage = Factory::NewFixedArrayWithHoles(result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008380 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008381 map = Factory::GetSlowElementsMap(Handle<Map>(result->map()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008382 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8383 uint32_t at_least_space_for = estimate_nof_elements +
8384 (estimate_nof_elements >> 2);
8385 storage = Handle<FixedArray>::cast(
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008386 Factory::NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008387 }
8388
8389 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
8390
8391 ArrayConcatVisitor visitor(storage, result_length, fast_case);
8392
8393 IterateArguments(arguments, &visitor);
8394
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008395 // Please note:
8396 // - the storage might have been changed in the visitor;
8397 // - the map and the storage must be set together to avoid breaking
8398 // the invariant that the map describes the array's elements.
8399 result->set_map(*map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008400 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008401 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008402
8403 return *result;
8404}
8405
8406
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008407// This will not allocate (flatten the string), but it may run
8408// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008409static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008410 NoHandleAllocation ha;
8411 ASSERT(args.length() == 1);
8412
8413 CONVERT_CHECKED(String, string, args[0]);
8414 StringInputBuffer buffer(string);
8415 while (buffer.has_more()) {
8416 uint16_t character = buffer.GetNext();
8417 PrintF("%c", character);
8418 }
8419 return string;
8420}
8421
ager@chromium.org5ec48922009-05-05 07:25:34 +00008422// Moves all own elements of an object, that are below a limit, to positions
8423// starting at zero. All undefined values are placed after non-undefined values,
8424// and are followed by non-existing element. Does not change the length
8425// property.
8426// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008427static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008428 ASSERT(args.length() == 2);
8429 CONVERT_CHECKED(JSObject, object, args[0]);
8430 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8431 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008432}
8433
8434
8435// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008436static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008437 ASSERT(args.length() == 2);
8438 CONVERT_CHECKED(JSArray, from, args[0]);
8439 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008440 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008441 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008442 if (new_elements->map() == Heap::fixed_array_map() ||
8443 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008444 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008445 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008446 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008447 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008448 Object* new_map;
8449 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008450 to->set_map(Map::cast(new_map));
8451 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008452 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008453 Object* obj;
8454 { MaybeObject* maybe_obj = from->ResetElements();
8455 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8456 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008457 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008458 return to;
8459}
8460
8461
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008462// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008463static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008464 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008465 CONVERT_CHECKED(JSObject, object, args[0]);
8466 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008467 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008468 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008469 } else if (object->IsJSArray()) {
8470 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008471 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008472 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008473 }
8474}
8475
8476
lrn@chromium.org303ada72010-10-27 09:33:13 +00008477static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008478 HandleScope handle_scope;
8479
8480 ASSERT_EQ(3, args.length());
8481
ager@chromium.orgac091b72010-05-05 07:34:42 +00008482 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008483 Handle<Object> key1 = args.at<Object>(1);
8484 Handle<Object> key2 = args.at<Object>(2);
8485
8486 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008487 if (!key1->ToArrayIndex(&index1)
8488 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008489 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008490 }
8491
ager@chromium.orgac091b72010-05-05 07:34:42 +00008492 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8493 Handle<Object> tmp1 = GetElement(jsobject, index1);
8494 Handle<Object> tmp2 = GetElement(jsobject, index2);
8495
8496 SetElement(jsobject, index1, tmp2);
8497 SetElement(jsobject, index2, tmp1);
8498
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008499 return Heap::undefined_value();
8500}
8501
8502
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008503// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008504// might have elements. Can either return keys (positive integers) or
8505// intervals (pair of a negative integer (-start-1) followed by a
8506// positive (length)) or undefined values.
8507// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008508static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008509 ASSERT(args.length() == 2);
8510 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008511 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008512 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008513 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008514 // Create an array and get all the keys into it, then remove all the
8515 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008516 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008517 int keys_length = keys->length();
8518 for (int i = 0; i < keys_length; i++) {
8519 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008520 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008521 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008522 // Zap invalid keys.
8523 keys->set_undefined(i);
8524 }
8525 }
8526 return *Factory::NewJSArrayWithElements(keys);
8527 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008528 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008529 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8530 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008531 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008532 uint32_t actual_length =
8533 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008534 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008535 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008536 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008537 single_interval->set(1, *length_object);
8538 return *Factory::NewJSArrayWithElements(single_interval);
8539 }
8540}
8541
8542
8543// DefineAccessor takes an optional final argument which is the
8544// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8545// to the way accessors are implemented, it is set for both the getter
8546// and setter on the first call to DefineAccessor and ignored on
8547// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008548static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008549 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8550 // Compute attributes.
8551 PropertyAttributes attributes = NONE;
8552 if (args.length() == 5) {
8553 CONVERT_CHECKED(Smi, attrs, args[4]);
8554 int value = attrs->value();
8555 // Only attribute bits should be set.
8556 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8557 attributes = static_cast<PropertyAttributes>(value);
8558 }
8559
8560 CONVERT_CHECKED(JSObject, obj, args[0]);
8561 CONVERT_CHECKED(String, name, args[1]);
8562 CONVERT_CHECKED(Smi, flag, args[2]);
8563 CONVERT_CHECKED(JSFunction, fun, args[3]);
8564 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8565}
8566
8567
lrn@chromium.org303ada72010-10-27 09:33:13 +00008568static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008569 ASSERT(args.length() == 3);
8570 CONVERT_CHECKED(JSObject, obj, args[0]);
8571 CONVERT_CHECKED(String, name, args[1]);
8572 CONVERT_CHECKED(Smi, flag, args[2]);
8573 return obj->LookupAccessor(name, flag->value() == 0);
8574}
8575
8576
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008577#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008578static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008579 ASSERT(args.length() == 0);
8580 return Execution::DebugBreakHelper();
8581}
8582
8583
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008584// Helper functions for wrapping and unwrapping stack frame ids.
8585static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008586 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008587 return Smi::FromInt(id >> 2);
8588}
8589
8590
8591static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8592 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8593}
8594
8595
8596// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008597// args[0]: debug event listener function to set or null or undefined for
8598// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008599// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008600static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008601 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008602 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8603 args[0]->IsUndefined() ||
8604 args[0]->IsNull());
8605 Handle<Object> callback = args.at<Object>(0);
8606 Handle<Object> data = args.at<Object>(1);
8607 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008608
8609 return Heap::undefined_value();
8610}
8611
8612
lrn@chromium.org303ada72010-10-27 09:33:13 +00008613static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008614 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008615 StackGuard::DebugBreak();
8616 return Heap::undefined_value();
8617}
8618
8619
lrn@chromium.org303ada72010-10-27 09:33:13 +00008620static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8621 LookupResult* result,
8622 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008623 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008624 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008625 case NORMAL:
8626 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008627 if (value->IsTheHole()) {
8628 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008629 }
8630 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008631 case FIELD:
8632 value =
8633 JSObject::cast(
8634 result->holder())->FastPropertyAt(result->GetFieldIndex());
8635 if (value->IsTheHole()) {
8636 return Heap::undefined_value();
8637 }
8638 return value;
8639 case CONSTANT_FUNCTION:
8640 return result->GetConstantFunction();
8641 case CALLBACKS: {
8642 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008643 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008644 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008645 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008646 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008647 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008648 ASSERT(maybe_value->IsException());
8649 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008650 Top::clear_pending_exception();
8651 if (caught_exception != NULL) {
8652 *caught_exception = true;
8653 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008654 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008655 }
8656 return value;
8657 } else {
8658 return Heap::undefined_value();
8659 }
8660 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008661 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008662 case MAP_TRANSITION:
8663 case CONSTANT_TRANSITION:
8664 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008665 return Heap::undefined_value();
8666 default:
8667 UNREACHABLE();
8668 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008669 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008670 return Heap::undefined_value();
8671}
8672
8673
ager@chromium.org32912102009-01-16 10:38:43 +00008674// Get debugger related details for an object property.
8675// args[0]: object holding property
8676// args[1]: name of the property
8677//
8678// The array returned contains the following information:
8679// 0: Property value
8680// 1: Property details
8681// 2: Property value is exception
8682// 3: Getter function if defined
8683// 4: Setter function if defined
8684// Items 2-4 are only filled if the property has either a getter or a setter
8685// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008686static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008687 HandleScope scope;
8688
8689 ASSERT(args.length() == 2);
8690
8691 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8692 CONVERT_ARG_CHECKED(String, name, 1);
8693
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008694 // Make sure to set the current context to the context before the debugger was
8695 // entered (if the debugger is entered). The reason for switching context here
8696 // is that for some property lookups (accessors and interceptors) callbacks
8697 // into the embedding application can occour, and the embedding application
8698 // could have the assumption that its own global context is the current
8699 // context and not some internal debugger context.
8700 SaveContext save;
8701 if (Debug::InDebugger()) {
8702 Top::set_context(*Debug::debugger_entry()->GetContext());
8703 }
8704
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008705 // Skip the global proxy as it has no properties and always delegates to the
8706 // real global object.
8707 if (obj->IsJSGlobalProxy()) {
8708 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8709 }
8710
8711
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008712 // Check if the name is trivially convertible to an index and get the element
8713 // if so.
8714 uint32_t index;
8715 if (name->AsArrayIndex(&index)) {
8716 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008717 Object* element_or_char;
8718 { MaybeObject* maybe_element_or_char =
8719 Runtime::GetElementOrCharAt(obj, index);
8720 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8721 return maybe_element_or_char;
8722 }
8723 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008724 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008725 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8726 return *Factory::NewJSArrayWithElements(details);
8727 }
8728
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008729 // Find the number of objects making up this.
8730 int length = LocalPrototypeChainLength(*obj);
8731
8732 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008733 Handle<JSObject> jsproto = obj;
8734 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008735 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008736 jsproto->LocalLookup(*name, &result);
8737 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008738 // LookupResult is not GC safe as it holds raw object pointers.
8739 // GC can happen later in this code so put the required fields into
8740 // local variables using handles when required for later use.
8741 PropertyType result_type = result.type();
8742 Handle<Object> result_callback_obj;
8743 if (result_type == CALLBACKS) {
8744 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8745 }
8746 Smi* property_details = result.GetPropertyDetails().AsSmi();
8747 // DebugLookupResultValue can cause GC so details from LookupResult needs
8748 // to be copied to handles before this.
8749 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008750 Object* raw_value;
8751 { MaybeObject* maybe_raw_value =
8752 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8753 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8754 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008755 Handle<Object> value(raw_value);
8756
8757 // If the callback object is a fixed array then it contains JavaScript
8758 // getter and/or setter.
8759 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8760 result_callback_obj->IsFixedArray();
8761 Handle<FixedArray> details =
8762 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8763 details->set(0, *value);
8764 details->set(1, property_details);
8765 if (hasJavaScriptAccessors) {
8766 details->set(2,
8767 caught_exception ? Heap::true_value()
8768 : Heap::false_value());
8769 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8770 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8771 }
8772
8773 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008774 }
8775 if (i < length - 1) {
8776 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8777 }
8778 }
8779
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008780 return Heap::undefined_value();
8781}
8782
8783
lrn@chromium.org303ada72010-10-27 09:33:13 +00008784static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008785 HandleScope scope;
8786
8787 ASSERT(args.length() == 2);
8788
8789 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8790 CONVERT_ARG_CHECKED(String, name, 1);
8791
8792 LookupResult result;
8793 obj->Lookup(*name, &result);
8794 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008795 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008796 }
8797 return Heap::undefined_value();
8798}
8799
8800
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008801// Return the property type calculated from the property details.
8802// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008803static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008804 ASSERT(args.length() == 1);
8805 CONVERT_CHECKED(Smi, details, args[0]);
8806 PropertyType type = PropertyDetails(details).type();
8807 return Smi::FromInt(static_cast<int>(type));
8808}
8809
8810
8811// Return the property attribute calculated from the property details.
8812// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008813static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008814 ASSERT(args.length() == 1);
8815 CONVERT_CHECKED(Smi, details, args[0]);
8816 PropertyAttributes attributes = PropertyDetails(details).attributes();
8817 return Smi::FromInt(static_cast<int>(attributes));
8818}
8819
8820
8821// Return the property insertion index calculated from the property details.
8822// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008823static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008824 ASSERT(args.length() == 1);
8825 CONVERT_CHECKED(Smi, details, args[0]);
8826 int index = PropertyDetails(details).index();
8827 return Smi::FromInt(index);
8828}
8829
8830
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008831// Return property value from named interceptor.
8832// args[0]: object
8833// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008834static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008835 HandleScope scope;
8836 ASSERT(args.length() == 2);
8837 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8838 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8839 CONVERT_ARG_CHECKED(String, name, 1);
8840
8841 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008842 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008843}
8844
8845
8846// Return element value from indexed interceptor.
8847// args[0]: object
8848// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008849static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8850 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008851 HandleScope scope;
8852 ASSERT(args.length() == 2);
8853 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8854 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8855 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8856
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008857 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008858}
8859
8860
lrn@chromium.org303ada72010-10-27 09:33:13 +00008861static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008862 ASSERT(args.length() >= 1);
8863 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008864 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008865 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008866 return Top::Throw(Heap::illegal_execution_state_symbol());
8867 }
8868
8869 return Heap::true_value();
8870}
8871
8872
lrn@chromium.org303ada72010-10-27 09:33:13 +00008873static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008874 HandleScope scope;
8875 ASSERT(args.length() == 1);
8876
8877 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008878 Object* result;
8879 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8880 if (!maybe_result->ToObject(&result)) return maybe_result;
8881 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008882
8883 // Count all frames which are relevant to debugging stack trace.
8884 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008885 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008886 if (id == StackFrame::NO_ID) {
8887 // If there is no JavaScript stack frame count is 0.
8888 return Smi::FromInt(0);
8889 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008890 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8891 return Smi::FromInt(n);
8892}
8893
8894
8895static const int kFrameDetailsFrameIdIndex = 0;
8896static const int kFrameDetailsReceiverIndex = 1;
8897static const int kFrameDetailsFunctionIndex = 2;
8898static const int kFrameDetailsArgumentCountIndex = 3;
8899static const int kFrameDetailsLocalCountIndex = 4;
8900static const int kFrameDetailsSourcePositionIndex = 5;
8901static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008902static const int kFrameDetailsAtReturnIndex = 7;
8903static const int kFrameDetailsDebuggerFrameIndex = 8;
8904static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008905
8906// Return an array with frame details
8907// args[0]: number: break id
8908// args[1]: number: frame index
8909//
8910// The array returned contains the following information:
8911// 0: Frame id
8912// 1: Receiver
8913// 2: Function
8914// 3: Argument count
8915// 4: Local count
8916// 5: Source position
8917// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008918// 7: Is at return
8919// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008920// Arguments name, value
8921// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008922// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00008923static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008924 HandleScope scope;
8925 ASSERT(args.length() == 2);
8926
8927 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008928 Object* check;
8929 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8930 if (!maybe_check->ToObject(&check)) return maybe_check;
8931 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008932 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8933
8934 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008935 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008936 if (id == StackFrame::NO_ID) {
8937 // If there are no JavaScript stack frames return undefined.
8938 return Heap::undefined_value();
8939 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008940 int count = 0;
8941 JavaScriptFrameIterator it(id);
8942 for (; !it.done(); it.Advance()) {
8943 if (count == index) break;
8944 count++;
8945 }
8946 if (it.done()) return Heap::undefined_value();
8947
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008948 bool is_optimized_frame =
8949 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
8950
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008951 // Traverse the saved contexts chain to find the active context for the
8952 // selected frame.
8953 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008954 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008955 save = save->prev();
8956 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008957 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008958
8959 // Get the frame id.
8960 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8961
8962 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008963 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008964
8965 // Check for constructor frame.
8966 bool constructor = it.frame()->IsConstructor();
8967
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008968 // Get scope info and read from it for local variable information.
8969 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008970 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008971 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008972
8973 // Get the context.
8974 Handle<Context> context(Context::cast(it.frame()->context()));
8975
8976 // Get the locals names and values into a temporary array.
8977 //
8978 // TODO(1240907): Hide compiler-introduced stack variables
8979 // (e.g. .result)? For users of the debugger, they will probably be
8980 // confusing.
8981 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008982
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008983 // Fill in the names of the locals.
8984 for (int i = 0; i < info.NumberOfLocals(); i++) {
8985 locals->set(i * 2, *info.LocalName(i));
8986 }
8987
8988 // Fill in the values of the locals.
8989 for (int i = 0; i < info.NumberOfLocals(); i++) {
8990 if (is_optimized_frame) {
8991 // If we are inspecting an optimized frame use undefined as the
8992 // value for all locals.
8993 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00008994 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008995 // for locals in optimized frames.
8996 locals->set(i * 2 + 1, Heap::undefined_value());
8997 } else if (i < info.number_of_stack_slots()) {
8998 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008999 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9000 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009001 // Traverse the context chain to the function context as all local
9002 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009003 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009004 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009005 context = Handle<Context>(context->previous());
9006 }
9007 ASSERT(context->is_function_context());
9008 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009009 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009010 }
9011 }
9012
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009013 // Check whether this frame is positioned at return. If not top
9014 // frame or if the frame is optimized it cannot be at a return.
9015 bool at_return = false;
9016 if (!is_optimized_frame && index == 0) {
9017 at_return = Debug::IsBreakAtReturn(it.frame());
9018 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009019
9020 // If positioned just before return find the value to be returned and add it
9021 // to the frame information.
9022 Handle<Object> return_value = Factory::undefined_value();
9023 if (at_return) {
9024 StackFrameIterator it2;
9025 Address internal_frame_sp = NULL;
9026 while (!it2.done()) {
9027 if (it2.frame()->is_internal()) {
9028 internal_frame_sp = it2.frame()->sp();
9029 } else {
9030 if (it2.frame()->is_java_script()) {
9031 if (it2.frame()->id() == it.frame()->id()) {
9032 // The internal frame just before the JavaScript frame contains the
9033 // value to return on top. A debug break at return will create an
9034 // internal frame to store the return value (eax/rax/r0) before
9035 // entering the debug break exit frame.
9036 if (internal_frame_sp != NULL) {
9037 return_value =
9038 Handle<Object>(Memory::Object_at(internal_frame_sp));
9039 break;
9040 }
9041 }
9042 }
9043
9044 // Indicate that the previous frame was not an internal frame.
9045 internal_frame_sp = NULL;
9046 }
9047 it2.Advance();
9048 }
9049 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009050
9051 // Now advance to the arguments adapter frame (if any). It contains all
9052 // the provided parameters whereas the function frame always have the number
9053 // of arguments matching the functions parameters. The rest of the
9054 // information (except for what is collected above) is the same.
9055 it.AdvanceToArgumentsFrame();
9056
9057 // Find the number of arguments to fill. At least fill the number of
9058 // parameters for the function and fill more if more parameters are provided.
9059 int argument_count = info.number_of_parameters();
9060 if (argument_count < it.frame()->GetProvidedParametersCount()) {
9061 argument_count = it.frame()->GetProvidedParametersCount();
9062 }
9063
9064 // Calculate the size of the result.
9065 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009066 2 * (argument_count + info.NumberOfLocals()) +
9067 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009068 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9069
9070 // Add the frame id.
9071 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9072
9073 // Add the function (same as in function frame).
9074 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9075
9076 // Add the arguments count.
9077 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9078
9079 // Add the locals count
9080 details->set(kFrameDetailsLocalCountIndex,
9081 Smi::FromInt(info.NumberOfLocals()));
9082
9083 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009084 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009085 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9086 } else {
9087 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
9088 }
9089
9090 // Add the constructor information.
9091 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
9092
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009093 // Add the at return information.
9094 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
9095
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009096 // Add information on whether this frame is invoked in the debugger context.
9097 details->set(kFrameDetailsDebuggerFrameIndex,
9098 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
9099
9100 // Fill the dynamic part.
9101 int details_index = kFrameDetailsFirstDynamicIndex;
9102
9103 // Add arguments name and value.
9104 for (int i = 0; i < argument_count; i++) {
9105 // Name of the argument.
9106 if (i < info.number_of_parameters()) {
9107 details->set(details_index++, *info.parameter_name(i));
9108 } else {
9109 details->set(details_index++, Heap::undefined_value());
9110 }
9111
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009112 // Parameter value. If we are inspecting an optimized frame, use
9113 // undefined as the value.
9114 //
9115 // TODO(3141533): We should be able to get the actual parameter
9116 // value for optimized frames.
9117 if (!is_optimized_frame &&
9118 (i < it.frame()->GetProvidedParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009119 details->set(details_index++, it.frame()->GetParameter(i));
9120 } else {
9121 details->set(details_index++, Heap::undefined_value());
9122 }
9123 }
9124
9125 // Add locals name and value from the temporary copy from the function frame.
9126 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9127 details->set(details_index++, locals->get(i));
9128 }
9129
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009130 // Add the value being returned.
9131 if (at_return) {
9132 details->set(details_index++, *return_value);
9133 }
9134
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009135 // Add the receiver (same as in function frame).
9136 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9137 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
9138 Handle<Object> receiver(it.frame()->receiver());
9139 if (!receiver->IsJSObject()) {
9140 // If the receiver is NOT a JSObject we have hit an optimization
9141 // where a value object is not converted into a wrapped JS objects.
9142 // To hide this optimization from the debugger, we wrap the receiver
9143 // by creating correct wrapper object based on the calling frame's
9144 // global context.
9145 it.Advance();
9146 Handle<Context> calling_frames_global_context(
9147 Context::cast(Context::cast(it.frame()->context())->global_context()));
9148 receiver = Factory::ToObject(receiver, calling_frames_global_context);
9149 }
9150 details->set(kFrameDetailsReceiverIndex, *receiver);
9151
9152 ASSERT_EQ(details_size, details_index);
9153 return *Factory::NewJSArrayWithElements(details);
9154}
9155
9156
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009157// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009158static bool CopyContextLocalsToScopeObject(
ager@chromium.orgb5737492010-07-15 09:29:43 +00009159 Handle<SerializedScopeInfo> serialized_scope_info,
9160 ScopeInfo<>& scope_info,
9161 Handle<Context> context,
9162 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009163 // Fill all context locals to the context extension.
9164 for (int i = Context::MIN_CONTEXT_SLOTS;
9165 i < scope_info.number_of_context_slots();
9166 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009167 int context_index = serialized_scope_info->ContextSlotIndex(
9168 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009169
9170 // Don't include the arguments shadow (.arguments) context variable.
9171 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009172 RETURN_IF_EMPTY_HANDLE_VALUE(
9173 SetProperty(scope_object,
9174 scope_info.context_slot_name(i),
9175 Handle<Object>(context->get(context_index)), NONE),
9176 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009177 }
9178 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009179
9180 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009181}
9182
9183
9184// Create a plain JSObject which materializes the local scope for the specified
9185// frame.
9186static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
9187 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009188 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009189 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9190 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009191
9192 // Allocate and initialize a JSObject with all the arguments, stack locals
9193 // heap locals and extension properties of the debugged function.
9194 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
9195
9196 // First fill all parameters.
9197 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009198 RETURN_IF_EMPTY_HANDLE_VALUE(
9199 SetProperty(local_scope,
9200 scope_info.parameter_name(i),
9201 Handle<Object>(frame->GetParameter(i)), NONE),
9202 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009203 }
9204
9205 // Second fill all stack locals.
9206 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009207 RETURN_IF_EMPTY_HANDLE_VALUE(
9208 SetProperty(local_scope,
9209 scope_info.stack_slot_name(i),
9210 Handle<Object>(frame->GetExpression(i)), NONE),
9211 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009212 }
9213
9214 // Third fill all context locals.
9215 Handle<Context> frame_context(Context::cast(frame->context()));
9216 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009217 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9218 function_context, local_scope)) {
9219 return Handle<JSObject>();
9220 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009221
9222 // Finally copy any properties from the function context extension. This will
9223 // be variables introduced by eval.
9224 if (function_context->closure() == *function) {
9225 if (function_context->has_extension() &&
9226 !function_context->IsGlobalContext()) {
9227 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009228 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009229 for (int i = 0; i < keys->length(); i++) {
9230 // Names of variables introduced by eval are strings.
9231 ASSERT(keys->get(i)->IsString());
9232 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009233 RETURN_IF_EMPTY_HANDLE_VALUE(
9234 SetProperty(local_scope, key, GetProperty(ext, key), NONE),
9235 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009236 }
9237 }
9238 }
9239 return local_scope;
9240}
9241
9242
9243// Create a plain JSObject which materializes the closure content for the
9244// context.
9245static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
9246 ASSERT(context->is_function_context());
9247
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009248 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009249 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9250 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009251
9252 // Allocate and initialize a JSObject with all the content of theis function
9253 // closure.
9254 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
9255
9256 // Check whether the arguments shadow object exists.
9257 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00009258 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
9259 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009260 if (arguments_shadow_index >= 0) {
9261 // In this case all the arguments are available in the arguments shadow
9262 // object.
9263 Handle<JSObject> arguments_shadow(
9264 JSObject::cast(context->get(arguments_shadow_index)));
9265 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009266 // We don't expect exception-throwing getters on the arguments shadow.
9267 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009268 RETURN_IF_EMPTY_HANDLE_VALUE(
9269 SetProperty(closure_scope,
9270 scope_info.parameter_name(i),
9271 Handle<Object>(element),
9272 NONE),
9273 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009274 }
9275 }
9276
9277 // Fill all context locals to the context extension.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009278 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9279 context, closure_scope)) {
9280 return Handle<JSObject>();
9281 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009282
9283 // Finally copy any properties from the function context extension. This will
9284 // be variables introduced by eval.
9285 if (context->has_extension()) {
9286 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009287 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009288 for (int i = 0; i < keys->length(); i++) {
9289 // Names of variables introduced by eval are strings.
9290 ASSERT(keys->get(i)->IsString());
9291 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009292 RETURN_IF_EMPTY_HANDLE_VALUE(
9293 SetProperty(closure_scope, key, GetProperty(ext, key), NONE),
9294 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009295 }
9296 }
9297
9298 return closure_scope;
9299}
9300
9301
9302// Iterate over the actual scopes visible from a stack frame. All scopes are
9303// backed by an actual context except the local scope, which is inserted
9304// "artifically" in the context chain.
9305class ScopeIterator {
9306 public:
9307 enum ScopeType {
9308 ScopeTypeGlobal = 0,
9309 ScopeTypeLocal,
9310 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009311 ScopeTypeClosure,
9312 // Every catch block contains an implicit with block (its parameter is
9313 // a JSContextExtensionObject) that extends current scope with a variable
9314 // holding exception object. Such with blocks are treated as scopes of their
9315 // own type.
9316 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009317 };
9318
9319 explicit ScopeIterator(JavaScriptFrame* frame)
9320 : frame_(frame),
9321 function_(JSFunction::cast(frame->function())),
9322 context_(Context::cast(frame->context())),
9323 local_done_(false),
9324 at_local_(false) {
9325
9326 // Check whether the first scope is actually a local scope.
9327 if (context_->IsGlobalContext()) {
9328 // If there is a stack slot for .result then this local scope has been
9329 // created for evaluating top level code and it is not a real local scope.
9330 // Checking for the existence of .result seems fragile, but the scope info
9331 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009332 int index = function_->shared()->scope_info()->
9333 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009334 at_local_ = index < 0;
9335 } else if (context_->is_function_context()) {
9336 at_local_ = true;
9337 }
9338 }
9339
9340 // More scopes?
9341 bool Done() { return context_.is_null(); }
9342
9343 // Move to the next scope.
9344 void Next() {
9345 // If at a local scope mark the local scope as passed.
9346 if (at_local_) {
9347 at_local_ = false;
9348 local_done_ = true;
9349
9350 // If the current context is not associated with the local scope the
9351 // current context is the next real scope, so don't move to the next
9352 // context in this case.
9353 if (context_->closure() != *function_) {
9354 return;
9355 }
9356 }
9357
9358 // The global scope is always the last in the chain.
9359 if (context_->IsGlobalContext()) {
9360 context_ = Handle<Context>();
9361 return;
9362 }
9363
9364 // Move to the next context.
9365 if (context_->is_function_context()) {
9366 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9367 } else {
9368 context_ = Handle<Context>(context_->previous());
9369 }
9370
9371 // If passing the local scope indicate that the current scope is now the
9372 // local scope.
9373 if (!local_done_ &&
9374 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9375 at_local_ = true;
9376 }
9377 }
9378
9379 // Return the type of the current scope.
9380 int Type() {
9381 if (at_local_) {
9382 return ScopeTypeLocal;
9383 }
9384 if (context_->IsGlobalContext()) {
9385 ASSERT(context_->global()->IsGlobalObject());
9386 return ScopeTypeGlobal;
9387 }
9388 if (context_->is_function_context()) {
9389 return ScopeTypeClosure;
9390 }
9391 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009392 // Current scope is either an explicit with statement or a with statement
9393 // implicitely generated for a catch block.
9394 // If the extension object here is a JSContextExtensionObject then
9395 // current with statement is one frome a catch block otherwise it's a
9396 // regular with statement.
9397 if (context_->extension()->IsJSContextExtensionObject()) {
9398 return ScopeTypeCatch;
9399 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009400 return ScopeTypeWith;
9401 }
9402
9403 // Return the JavaScript object with the content of the current scope.
9404 Handle<JSObject> ScopeObject() {
9405 switch (Type()) {
9406 case ScopeIterator::ScopeTypeGlobal:
9407 return Handle<JSObject>(CurrentContext()->global());
9408 break;
9409 case ScopeIterator::ScopeTypeLocal:
9410 // Materialize the content of the local scope into a JSObject.
9411 return MaterializeLocalScope(frame_);
9412 break;
9413 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009414 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009415 // Return the with object.
9416 return Handle<JSObject>(CurrentContext()->extension());
9417 break;
9418 case ScopeIterator::ScopeTypeClosure:
9419 // Materialize the content of the closure scope into a JSObject.
9420 return MaterializeClosure(CurrentContext());
9421 break;
9422 }
9423 UNREACHABLE();
9424 return Handle<JSObject>();
9425 }
9426
9427 // Return the context for this scope. For the local context there might not
9428 // be an actual context.
9429 Handle<Context> CurrentContext() {
9430 if (at_local_ && context_->closure() != *function_) {
9431 return Handle<Context>();
9432 }
9433 return context_;
9434 }
9435
9436#ifdef DEBUG
9437 // Debug print of the content of the current scope.
9438 void DebugPrint() {
9439 switch (Type()) {
9440 case ScopeIterator::ScopeTypeGlobal:
9441 PrintF("Global:\n");
9442 CurrentContext()->Print();
9443 break;
9444
9445 case ScopeIterator::ScopeTypeLocal: {
9446 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009447 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009448 scope_info.Print();
9449 if (!CurrentContext().is_null()) {
9450 CurrentContext()->Print();
9451 if (CurrentContext()->has_extension()) {
9452 Handle<JSObject> extension =
9453 Handle<JSObject>(CurrentContext()->extension());
9454 if (extension->IsJSContextExtensionObject()) {
9455 extension->Print();
9456 }
9457 }
9458 }
9459 break;
9460 }
9461
9462 case ScopeIterator::ScopeTypeWith: {
9463 PrintF("With:\n");
9464 Handle<JSObject> extension =
9465 Handle<JSObject>(CurrentContext()->extension());
9466 extension->Print();
9467 break;
9468 }
9469
ager@chromium.orga1645e22009-09-09 19:27:10 +00009470 case ScopeIterator::ScopeTypeCatch: {
9471 PrintF("Catch:\n");
9472 Handle<JSObject> extension =
9473 Handle<JSObject>(CurrentContext()->extension());
9474 extension->Print();
9475 break;
9476 }
9477
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009478 case ScopeIterator::ScopeTypeClosure: {
9479 PrintF("Closure:\n");
9480 CurrentContext()->Print();
9481 if (CurrentContext()->has_extension()) {
9482 Handle<JSObject> extension =
9483 Handle<JSObject>(CurrentContext()->extension());
9484 if (extension->IsJSContextExtensionObject()) {
9485 extension->Print();
9486 }
9487 }
9488 break;
9489 }
9490
9491 default:
9492 UNREACHABLE();
9493 }
9494 PrintF("\n");
9495 }
9496#endif
9497
9498 private:
9499 JavaScriptFrame* frame_;
9500 Handle<JSFunction> function_;
9501 Handle<Context> context_;
9502 bool local_done_;
9503 bool at_local_;
9504
9505 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9506};
9507
9508
lrn@chromium.org303ada72010-10-27 09:33:13 +00009509static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009510 HandleScope scope;
9511 ASSERT(args.length() == 2);
9512
9513 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009514 Object* check;
9515 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9516 if (!maybe_check->ToObject(&check)) return maybe_check;
9517 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009518 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9519
9520 // Get the frame where the debugging is performed.
9521 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9522 JavaScriptFrameIterator it(id);
9523 JavaScriptFrame* frame = it.frame();
9524
9525 // Count the visible scopes.
9526 int n = 0;
9527 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9528 n++;
9529 }
9530
9531 return Smi::FromInt(n);
9532}
9533
9534
9535static const int kScopeDetailsTypeIndex = 0;
9536static const int kScopeDetailsObjectIndex = 1;
9537static const int kScopeDetailsSize = 2;
9538
9539// Return an array with scope details
9540// args[0]: number: break id
9541// args[1]: number: frame index
9542// args[2]: number: scope index
9543//
9544// The array returned contains the following information:
9545// 0: Scope type
9546// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009547static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009548 HandleScope scope;
9549 ASSERT(args.length() == 3);
9550
9551 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009552 Object* check;
9553 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9554 if (!maybe_check->ToObject(&check)) return maybe_check;
9555 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009556 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9557 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9558
9559 // Get the frame where the debugging is performed.
9560 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9561 JavaScriptFrameIterator frame_it(id);
9562 JavaScriptFrame* frame = frame_it.frame();
9563
9564 // Find the requested scope.
9565 int n = 0;
9566 ScopeIterator it(frame);
9567 for (; !it.Done() && n < index; it.Next()) {
9568 n++;
9569 }
9570 if (it.Done()) {
9571 return Heap::undefined_value();
9572 }
9573
9574 // Calculate the size of the result.
9575 int details_size = kScopeDetailsSize;
9576 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9577
9578 // Fill in scope details.
9579 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009580 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009581 RETURN_IF_EMPTY_HANDLE(scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009582 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009583
9584 return *Factory::NewJSArrayWithElements(details);
9585}
9586
9587
lrn@chromium.org303ada72010-10-27 09:33:13 +00009588static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009589 HandleScope scope;
9590 ASSERT(args.length() == 0);
9591
9592#ifdef DEBUG
9593 // Print the scopes for the top frame.
9594 StackFrameLocator locator;
9595 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9596 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9597 it.DebugPrint();
9598 }
9599#endif
9600 return Heap::undefined_value();
9601}
9602
9603
lrn@chromium.org303ada72010-10-27 09:33:13 +00009604static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009605 HandleScope scope;
9606 ASSERT(args.length() == 1);
9607
9608 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009609 Object* result;
9610 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9611 if (!maybe_result->ToObject(&result)) return maybe_result;
9612 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009613
9614 // Count all archived V8 threads.
9615 int n = 0;
9616 for (ThreadState* thread = ThreadState::FirstInUse();
9617 thread != NULL;
9618 thread = thread->Next()) {
9619 n++;
9620 }
9621
9622 // Total number of threads is current thread and archived threads.
9623 return Smi::FromInt(n + 1);
9624}
9625
9626
9627static const int kThreadDetailsCurrentThreadIndex = 0;
9628static const int kThreadDetailsThreadIdIndex = 1;
9629static const int kThreadDetailsSize = 2;
9630
9631// Return an array with thread details
9632// args[0]: number: break id
9633// args[1]: number: thread index
9634//
9635// The array returned contains the following information:
9636// 0: Is current thread?
9637// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009638static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009639 HandleScope scope;
9640 ASSERT(args.length() == 2);
9641
9642 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009643 Object* check;
9644 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9645 if (!maybe_check->ToObject(&check)) return maybe_check;
9646 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009647 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9648
9649 // Allocate array for result.
9650 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9651
9652 // Thread index 0 is current thread.
9653 if (index == 0) {
9654 // Fill the details.
9655 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9656 details->set(kThreadDetailsThreadIdIndex,
9657 Smi::FromInt(ThreadManager::CurrentId()));
9658 } else {
9659 // Find the thread with the requested index.
9660 int n = 1;
9661 ThreadState* thread = ThreadState::FirstInUse();
9662 while (index != n && thread != NULL) {
9663 thread = thread->Next();
9664 n++;
9665 }
9666 if (thread == NULL) {
9667 return Heap::undefined_value();
9668 }
9669
9670 // Fill the details.
9671 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9672 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9673 }
9674
9675 // Convert to JS array and return.
9676 return *Factory::NewJSArrayWithElements(details);
9677}
9678
9679
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009680// Sets the disable break state
9681// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009682static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009683 HandleScope scope;
9684 ASSERT(args.length() == 1);
9685 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9686 Debug::set_disable_break(disable_break);
9687 return Heap::undefined_value();
9688}
9689
9690
lrn@chromium.org303ada72010-10-27 09:33:13 +00009691static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009692 HandleScope scope;
9693 ASSERT(args.length() == 1);
9694
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009695 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9696 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009697 // Find the number of break points
9698 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9699 if (break_locations->IsUndefined()) return Heap::undefined_value();
9700 // Return array as JS array
9701 return *Factory::NewJSArrayWithElements(
9702 Handle<FixedArray>::cast(break_locations));
9703}
9704
9705
9706// Set a break point in a function
9707// args[0]: function
9708// args[1]: number: break source position (within the function source)
9709// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009710static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009711 HandleScope scope;
9712 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009713 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9714 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009715 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9716 RUNTIME_ASSERT(source_position >= 0);
9717 Handle<Object> break_point_object_arg = args.at<Object>(2);
9718
9719 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009720 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009721
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009722 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009723}
9724
9725
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009726Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9727 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009728 // Iterate the heap looking for SharedFunctionInfo generated from the
9729 // script. The inner most SharedFunctionInfo containing the source position
9730 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009731 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009732 // which is found is not compiled it is compiled and the heap is iterated
9733 // again as the compilation might create inner functions from the newly
9734 // compiled function and the actual requested break point might be in one of
9735 // these functions.
9736 bool done = false;
9737 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009738 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009739 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009740 while (!done) {
9741 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009742 for (HeapObject* obj = iterator.next();
9743 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009744 if (obj->IsSharedFunctionInfo()) {
9745 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9746 if (shared->script() == *script) {
9747 // If the SharedFunctionInfo found has the requested script data and
9748 // contains the source position it is a candidate.
9749 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009750 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009751 start_position = shared->start_position();
9752 }
9753 if (start_position <= position &&
9754 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009755 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009756 // candidate this is the new candidate.
9757 if (target.is_null()) {
9758 target_start_position = start_position;
9759 target = shared;
9760 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009761 if (target_start_position == start_position &&
9762 shared->end_position() == target->end_position()) {
9763 // If a top-level function contain only one function
9764 // declartion the source for the top-level and the function is
9765 // the same. In that case prefer the non top-level function.
9766 if (!shared->is_toplevel()) {
9767 target_start_position = start_position;
9768 target = shared;
9769 }
9770 } else if (target_start_position <= start_position &&
9771 shared->end_position() <= target->end_position()) {
9772 // This containment check includes equality as a function inside
9773 // a top-level function can share either start or end position
9774 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009775 target_start_position = start_position;
9776 target = shared;
9777 }
9778 }
9779 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009780 }
9781 }
9782 }
9783
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009784 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009785 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009786 }
9787
9788 // If the candidate found is compiled we are done. NOTE: when lazy
9789 // compilation of inner functions is introduced some additional checking
9790 // needs to be done here to compile inner functions.
9791 done = target->is_compiled();
9792 if (!done) {
9793 // If the candidate is not compiled compile it to reveal any inner
9794 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009795 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009796 }
9797 }
9798
9799 return *target;
9800}
9801
9802
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009803// Changes the state of a break point in a script and returns source position
9804// where break point was set. NOTE: Regarding performance see the NOTE for
9805// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009806// args[0]: script to set break point in
9807// args[1]: number: break source position (within the script source)
9808// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009809static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009810 HandleScope scope;
9811 ASSERT(args.length() == 3);
9812 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9813 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9814 RUNTIME_ASSERT(source_position >= 0);
9815 Handle<Object> break_point_object_arg = args.at<Object>(2);
9816
9817 // Get the script from the script wrapper.
9818 RUNTIME_ASSERT(wrapper->value()->IsScript());
9819 Handle<Script> script(Script::cast(wrapper->value()));
9820
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009821 Object* result = Runtime::FindSharedFunctionInfoInScript(
9822 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009823 if (!result->IsUndefined()) {
9824 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9825 // Find position within function. The script position might be before the
9826 // source position of the first function.
9827 int position;
9828 if (shared->start_position() > source_position) {
9829 position = 0;
9830 } else {
9831 position = source_position - shared->start_position();
9832 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009833 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9834 position += shared->start_position();
9835 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009836 }
9837 return Heap::undefined_value();
9838}
9839
9840
9841// Clear a break point
9842// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009843static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009844 HandleScope scope;
9845 ASSERT(args.length() == 1);
9846 Handle<Object> break_point_object_arg = args.at<Object>(0);
9847
9848 // Clear break point.
9849 Debug::ClearBreakPoint(break_point_object_arg);
9850
9851 return Heap::undefined_value();
9852}
9853
9854
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009855// Change the state of break on exceptions.
9856// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9857// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009858static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009859 HandleScope scope;
9860 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009861 RUNTIME_ASSERT(args[0]->IsNumber());
9862 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009863
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009864 // If the number doesn't match an enum value, the ChangeBreakOnException
9865 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009866 ExceptionBreakType type =
9867 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009868 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009869 Debug::ChangeBreakOnException(type, enable);
9870 return Heap::undefined_value();
9871}
9872
9873
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009874// Returns the state of break on exceptions
9875// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009876static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009877 HandleScope scope;
9878 ASSERT(args.length() == 1);
9879 RUNTIME_ASSERT(args[0]->IsNumber());
9880
9881 ExceptionBreakType type =
9882 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9883 bool result = Debug::IsBreakOnException(type);
9884 return Smi::FromInt(result);
9885}
9886
9887
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009888// Prepare for stepping
9889// args[0]: break id for checking execution state
9890// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009891// args[2]: number of times to perform the step, for step out it is the number
9892// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009893static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009894 HandleScope scope;
9895 ASSERT(args.length() == 3);
9896 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009897 Object* check;
9898 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9899 if (!maybe_check->ToObject(&check)) return maybe_check;
9900 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009901 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9902 return Top::Throw(Heap::illegal_argument_symbol());
9903 }
9904
9905 // Get the step action and check validity.
9906 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9907 if (step_action != StepIn &&
9908 step_action != StepNext &&
9909 step_action != StepOut &&
9910 step_action != StepInMin &&
9911 step_action != StepMin) {
9912 return Top::Throw(Heap::illegal_argument_symbol());
9913 }
9914
9915 // Get the number of steps.
9916 int step_count = NumberToInt32(args[2]);
9917 if (step_count < 1) {
9918 return Top::Throw(Heap::illegal_argument_symbol());
9919 }
9920
ager@chromium.orga1645e22009-09-09 19:27:10 +00009921 // Clear all current stepping setup.
9922 Debug::ClearStepping();
9923
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009924 // Prepare step.
9925 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9926 return Heap::undefined_value();
9927}
9928
9929
9930// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009931static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009932 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009933 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009934 Debug::ClearStepping();
9935 return Heap::undefined_value();
9936}
9937
9938
9939// Creates a copy of the with context chain. The copy of the context chain is
9940// is linked to the function context supplied.
9941static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9942 Handle<Context> function_context) {
9943 // At the bottom of the chain. Return the function context to link to.
9944 if (context_chain->is_function_context()) {
9945 return function_context;
9946 }
9947
9948 // Recursively copy the with contexts.
9949 Handle<Context> previous(context_chain->previous());
9950 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009951 Handle<Context> context = CopyWithContextChain(function_context, previous);
9952 return Factory::NewWithContext(context,
9953 extension,
9954 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009955}
9956
9957
9958// Helper function to find or create the arguments object for
9959// Runtime_DebugEvaluate.
9960static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9961 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009962 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009963 const ScopeInfo<>* sinfo,
9964 Handle<Context> function_context) {
9965 // Try to find the value of 'arguments' to pass as parameter. If it is not
9966 // found (that is the debugged function does not reference 'arguments' and
9967 // does not support eval) then create an 'arguments' object.
9968 int index;
9969 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009970 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009971 if (index != -1) {
9972 return Handle<Object>(frame->GetExpression(index));
9973 }
9974 }
9975
9976 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009977 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009978 if (index != -1) {
9979 return Handle<Object>(function_context->get(index));
9980 }
9981 }
9982
9983 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009984 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9985 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009986
9987 AssertNoAllocation no_gc;
9988 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009989 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009990 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009991 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009992 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009993 return arguments;
9994}
9995
9996
9997// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009998// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009999// extension part has all the parameters and locals of the function on the
10000// stack frame. A function which calls eval with the code to evaluate is then
10001// compiled in this context and called in this context. As this context
10002// replaces the context of the function on the stack frame a new (empty)
10003// function is created as well to be used as the closure for the context.
10004// This function and the context acts as replacements for the function on the
10005// stack frame presenting the same view of the values of parameters and
10006// local variables as if the piece of JavaScript was evaluated at the point
10007// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010008static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010009 HandleScope scope;
10010
10011 // Check the execution state and decode arguments frame and source to be
10012 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010013 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010014 Object* check_result;
10015 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10016 if (!maybe_check_result->ToObject(&check_result)) {
10017 return maybe_check_result;
10018 }
10019 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010020 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10021 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010022 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010023 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010024
10025 // Handle the processing of break.
10026 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010027
10028 // Get the frame where the debugging is performed.
10029 StackFrame::Id id = UnwrapFrameId(wrapped_id);
10030 JavaScriptFrameIterator it(id);
10031 JavaScriptFrame* frame = it.frame();
10032 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010033 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010034 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010035
10036 // Traverse the saved contexts chain to find the active context for the
10037 // selected frame.
10038 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010039 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010040 save = save->prev();
10041 }
10042 ASSERT(save != NULL);
10043 SaveContext savex;
10044 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010045
10046 // Create the (empty) function replacing the function on the stack frame for
10047 // the purpose of evaluating in the context created below. It is important
10048 // that this function does not describe any parameters and local variables
10049 // in the context. If it does then this will cause problems with the lookup
10050 // in Context::Lookup, where context slots for parameters and local variables
10051 // are looked at before the extension object.
10052 Handle<JSFunction> go_between =
10053 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
10054 go_between->set_context(function->context());
10055#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010056 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010057 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10058 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10059#endif
10060
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010061 // Materialize the content of the local scope into a JSObject.
10062 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010063 RETURN_IF_EMPTY_HANDLE(local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010064
10065 // Allocate a new context for the debug evaluation and set the extension
10066 // object build.
10067 Handle<Context> context =
10068 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010069 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010070 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010071 Handle<Context> frame_context(Context::cast(frame->context()));
10072 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010073 context = CopyWithContextChain(frame_context, context);
10074
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010075 if (additional_context->IsJSObject()) {
10076 context = Factory::NewWithContext(context,
10077 Handle<JSObject>::cast(additional_context), false);
10078 }
10079
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010080 // Wrap the evaluation statement in a new function compiled in the newly
10081 // created context. The function has one parameter which has to be called
10082 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010083 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010084 // function(arguments,__source__) {return eval(__source__);}
10085 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000010086 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010087 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010088 Handle<String> function_source =
10089 Factory::NewStringFromAscii(Vector<const char>(source_str,
10090 source_str_length));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010091
10092 // Currently, the eval code will be executed in non-strict mode,
10093 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010094 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010095 Compiler::CompileEval(function_source,
10096 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010097 context->IsGlobalContext(),
10098 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010099 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010100 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010101 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010102
10103 // Invoke the result of the compilation to get the evaluation function.
10104 bool has_pending_exception;
10105 Handle<Object> receiver(frame->receiver());
10106 Handle<Object> evaluation_function =
10107 Execution::Call(compiled_function, receiver, 0, NULL,
10108 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010109 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010110
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010111 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
10112 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010113
10114 // Invoke the evaluation function and return the result.
10115 const int argc = 2;
10116 Object** argv[argc] = { arguments.location(),
10117 Handle<Object>::cast(source).location() };
10118 Handle<Object> result =
10119 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10120 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010121 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010122
10123 // Skip the global proxy as it has no properties and always delegates to the
10124 // real global object.
10125 if (result->IsJSGlobalProxy()) {
10126 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10127 }
10128
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010129 return *result;
10130}
10131
10132
lrn@chromium.org303ada72010-10-27 09:33:13 +000010133static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010134 HandleScope scope;
10135
10136 // Check the execution state and decode arguments frame and source to be
10137 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010138 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010139 Object* check_result;
10140 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10141 if (!maybe_check_result->ToObject(&check_result)) {
10142 return maybe_check_result;
10143 }
10144 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010145 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010146 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010147 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010148
10149 // Handle the processing of break.
10150 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010151
10152 // Enter the top context from before the debugger was invoked.
10153 SaveContext save;
10154 SaveContext* top = &save;
10155 while (top != NULL && *top->context() == *Debug::debug_context()) {
10156 top = top->prev();
10157 }
10158 if (top != NULL) {
10159 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010160 }
10161
10162 // Get the global context now set to the top context from before the
10163 // debugger was invoked.
10164 Handle<Context> context = Top::global_context();
10165
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010166 bool is_global = true;
10167
10168 if (additional_context->IsJSObject()) {
10169 // Create a function context first, than put 'with' context on top of it.
10170 Handle<JSFunction> go_between = Factory::NewFunction(
10171 Factory::empty_string(), Factory::undefined_value());
10172 go_between->set_context(*context);
10173 context =
10174 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
10175 context->set_extension(JSObject::cast(*additional_context));
10176 is_global = false;
10177 }
10178
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010179 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010180 // Currently, the eval code will be executed in non-strict mode,
10181 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010182 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010183 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010184 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010185 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010186 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
10187 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010188
10189 // Invoke the result of the compilation to get the evaluation function.
10190 bool has_pending_exception;
10191 Handle<Object> receiver = Top::global();
10192 Handle<Object> result =
10193 Execution::Call(compiled_function, receiver, 0, NULL,
10194 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010195 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010196 return *result;
10197}
10198
10199
lrn@chromium.org303ada72010-10-27 09:33:13 +000010200static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010201 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +000010202 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010203
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010204 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010205 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010206
10207 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010208 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010209 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10210 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10211 // because using
10212 // instances->set(i, *GetScriptWrapper(script))
10213 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10214 // already have deferenced the instances handle.
10215 Handle<JSValue> wrapper = GetScriptWrapper(script);
10216 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010217 }
10218
10219 // Return result as a JS array.
10220 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
10221 Handle<JSArray>::cast(result)->SetContent(*instances);
10222 return *result;
10223}
10224
10225
10226// Helper function used by Runtime_DebugReferencedBy below.
10227static int DebugReferencedBy(JSObject* target,
10228 Object* instance_filter, int max_references,
10229 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010230 JSFunction* arguments_function) {
10231 NoHandleAllocation ha;
10232 AssertNoAllocation no_alloc;
10233
10234 // Iterate the heap.
10235 int count = 0;
10236 JSObject* last = NULL;
10237 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010238 HeapObject* heap_obj = NULL;
10239 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010240 (max_references == 0 || count < max_references)) {
10241 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010242 if (heap_obj->IsJSObject()) {
10243 // Skip context extension objects and argument arrays as these are
10244 // checked in the context of functions using them.
10245 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010246 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010247 obj->map()->constructor() == arguments_function) {
10248 continue;
10249 }
10250
10251 // Check if the JS object has a reference to the object looked for.
10252 if (obj->ReferencesObject(target)) {
10253 // Check instance filter if supplied. This is normally used to avoid
10254 // references from mirror objects (see Runtime_IsInPrototypeChain).
10255 if (!instance_filter->IsUndefined()) {
10256 Object* V = obj;
10257 while (true) {
10258 Object* prototype = V->GetPrototype();
10259 if (prototype->IsNull()) {
10260 break;
10261 }
10262 if (instance_filter == prototype) {
10263 obj = NULL; // Don't add this object.
10264 break;
10265 }
10266 V = prototype;
10267 }
10268 }
10269
10270 if (obj != NULL) {
10271 // Valid reference found add to instance array if supplied an update
10272 // count.
10273 if (instances != NULL && count < instances_size) {
10274 instances->set(count, obj);
10275 }
10276 last = obj;
10277 count++;
10278 }
10279 }
10280 }
10281 }
10282
10283 // Check for circular reference only. This can happen when the object is only
10284 // referenced from mirrors and has a circular reference in which case the
10285 // object is not really alive and would have been garbage collected if not
10286 // referenced from the mirror.
10287 if (count == 1 && last == target) {
10288 count = 0;
10289 }
10290
10291 // Return the number of referencing objects found.
10292 return count;
10293}
10294
10295
10296// Scan the heap for objects with direct references to an object
10297// args[0]: the object to find references to
10298// args[1]: constructor function for instances to exclude (Mirror)
10299// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010300static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010301 ASSERT(args.length() == 3);
10302
10303 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010304 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010305
10306 // Check parameters.
10307 CONVERT_CHECKED(JSObject, target, args[0]);
10308 Object* instance_filter = args[1];
10309 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10310 instance_filter->IsJSObject());
10311 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10312 RUNTIME_ASSERT(max_references >= 0);
10313
10314 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010315 JSObject* arguments_boilerplate =
10316 Top::context()->global_context()->arguments_boilerplate();
10317 JSFunction* arguments_function =
10318 JSFunction::cast(arguments_boilerplate->map()->constructor());
10319
10320 // Get the number of referencing objects.
10321 int count;
10322 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010323 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010324
10325 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010326 Object* object;
10327 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10328 if (!maybe_object->ToObject(&object)) return maybe_object;
10329 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010330 FixedArray* instances = FixedArray::cast(object);
10331
10332 // Fill the referencing objects.
10333 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010334 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010335
10336 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010337 Object* result;
10338 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10339 Top::context()->global_context()->array_function());
10340 if (!maybe_result->ToObject(&result)) return maybe_result;
10341 }
10342 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010343 return result;
10344}
10345
10346
10347// Helper function used by Runtime_DebugConstructedBy below.
10348static int DebugConstructedBy(JSFunction* constructor, int max_references,
10349 FixedArray* instances, int instances_size) {
10350 AssertNoAllocation no_alloc;
10351
10352 // Iterate the heap.
10353 int count = 0;
10354 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010355 HeapObject* heap_obj = NULL;
10356 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010357 (max_references == 0 || count < max_references)) {
10358 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010359 if (heap_obj->IsJSObject()) {
10360 JSObject* obj = JSObject::cast(heap_obj);
10361 if (obj->map()->constructor() == constructor) {
10362 // Valid reference found add to instance array if supplied an update
10363 // count.
10364 if (instances != NULL && count < instances_size) {
10365 instances->set(count, obj);
10366 }
10367 count++;
10368 }
10369 }
10370 }
10371
10372 // Return the number of referencing objects found.
10373 return count;
10374}
10375
10376
10377// Scan the heap for objects constructed by a specific function.
10378// args[0]: the constructor to find instances of
10379// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010380static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010381 ASSERT(args.length() == 2);
10382
10383 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010384 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010385
10386 // Check parameters.
10387 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10388 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10389 RUNTIME_ASSERT(max_references >= 0);
10390
10391 // Get the number of referencing objects.
10392 int count;
10393 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10394
10395 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010396 Object* object;
10397 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10398 if (!maybe_object->ToObject(&object)) return maybe_object;
10399 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010400 FixedArray* instances = FixedArray::cast(object);
10401
10402 // Fill the referencing objects.
10403 count = DebugConstructedBy(constructor, max_references, instances, count);
10404
10405 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010406 Object* result;
10407 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10408 Top::context()->global_context()->array_function());
10409 if (!maybe_result->ToObject(&result)) return maybe_result;
10410 }
10411 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010412 return result;
10413}
10414
10415
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010416// Find the effective prototype object as returned by __proto__.
10417// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010418static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010419 ASSERT(args.length() == 1);
10420
10421 CONVERT_CHECKED(JSObject, obj, args[0]);
10422
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010423 // Use the __proto__ accessor.
10424 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010425}
10426
10427
lrn@chromium.org303ada72010-10-27 09:33:13 +000010428static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010429 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010430 CPU::DebugBreak();
10431 return Heap::undefined_value();
10432}
10433
10434
lrn@chromium.org303ada72010-10-27 09:33:13 +000010435static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010436#ifdef DEBUG
10437 HandleScope scope;
10438 ASSERT(args.length() == 1);
10439 // Get the function and make sure it is compiled.
10440 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010441 Handle<SharedFunctionInfo> shared(func->shared());
10442 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010443 return Failure::Exception();
10444 }
10445 func->code()->PrintLn();
10446#endif // DEBUG
10447 return Heap::undefined_value();
10448}
ager@chromium.org9085a012009-05-11 19:22:57 +000010449
10450
lrn@chromium.org303ada72010-10-27 09:33:13 +000010451static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010452#ifdef DEBUG
10453 HandleScope scope;
10454 ASSERT(args.length() == 1);
10455 // Get the function and make sure it is compiled.
10456 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010457 Handle<SharedFunctionInfo> shared(func->shared());
10458 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010459 return Failure::Exception();
10460 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010461 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010462#endif // DEBUG
10463 return Heap::undefined_value();
10464}
10465
10466
lrn@chromium.org303ada72010-10-27 09:33:13 +000010467static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010468 NoHandleAllocation ha;
10469 ASSERT(args.length() == 1);
10470
10471 CONVERT_CHECKED(JSFunction, f, args[0]);
10472 return f->shared()->inferred_name();
10473}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010474
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010475
10476static int FindSharedFunctionInfosForScript(Script* script,
10477 FixedArray* buffer) {
10478 AssertNoAllocation no_allocations;
10479
10480 int counter = 0;
10481 int buffer_size = buffer->length();
10482 HeapIterator iterator;
10483 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10484 ASSERT(obj != NULL);
10485 if (!obj->IsSharedFunctionInfo()) {
10486 continue;
10487 }
10488 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10489 if (shared->script() != script) {
10490 continue;
10491 }
10492 if (counter < buffer_size) {
10493 buffer->set(counter, shared);
10494 }
10495 counter++;
10496 }
10497 return counter;
10498}
10499
10500// For a script finds all SharedFunctionInfo's in the heap that points
10501// to this script. Returns JSArray of SharedFunctionInfo wrapped
10502// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010503static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010504 Arguments args) {
10505 ASSERT(args.length() == 1);
10506 HandleScope scope;
10507 CONVERT_CHECKED(JSValue, script_value, args[0]);
10508
10509 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10510
10511 const int kBufferSize = 32;
10512
10513 Handle<FixedArray> array;
10514 array = Factory::NewFixedArray(kBufferSize);
10515 int number = FindSharedFunctionInfosForScript(*script, *array);
10516 if (number > kBufferSize) {
10517 array = Factory::NewFixedArray(number);
10518 FindSharedFunctionInfosForScript(*script, *array);
10519 }
10520
10521 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10522 result->set_length(Smi::FromInt(number));
10523
10524 LiveEdit::WrapSharedFunctionInfos(result);
10525
10526 return *result;
10527}
10528
10529// For a script calculates compilation information about all its functions.
10530// The script source is explicitly specified by the second argument.
10531// The source of the actual script is not used, however it is important that
10532// all generated code keeps references to this particular instance of script.
10533// Returns a JSArray of compilation infos. The array is ordered so that
10534// each function with all its descendant is always stored in a continues range
10535// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010536static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010537 ASSERT(args.length() == 2);
10538 HandleScope scope;
10539 CONVERT_CHECKED(JSValue, script, args[0]);
10540 CONVERT_ARG_CHECKED(String, source, 1);
10541 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10542
10543 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10544
10545 if (Top::has_pending_exception()) {
10546 return Failure::Exception();
10547 }
10548
10549 return result;
10550}
10551
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010552// Changes the source of the script to a new_source.
10553// If old_script_name is provided (i.e. is a String), also creates a copy of
10554// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010555static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010556 ASSERT(args.length() == 3);
10557 HandleScope scope;
10558 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10559 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010560 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010561
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010562 CONVERT_CHECKED(Script, original_script_pointer,
10563 original_script_value->value());
10564 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010565
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010566 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10567 new_source,
10568 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010569
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010570 if (old_script->IsScript()) {
10571 Handle<Script> script_handle(Script::cast(old_script));
10572 return *(GetScriptWrapper(script_handle));
10573 } else {
10574 return Heap::null_value();
10575 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010576}
10577
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010578
10579static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10580 ASSERT(args.length() == 1);
10581 HandleScope scope;
10582 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10583 return LiveEdit::FunctionSourceUpdated(shared_info);
10584}
10585
10586
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010587// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010588static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010589 ASSERT(args.length() == 2);
10590 HandleScope scope;
10591 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10592 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10593
ager@chromium.orgac091b72010-05-05 07:34:42 +000010594 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010595}
10596
10597// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010598static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010599 ASSERT(args.length() == 2);
10600 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010601 Handle<Object> function_object(args[0]);
10602 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010603
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010604 if (function_object->IsJSValue()) {
10605 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10606 if (script_object->IsJSValue()) {
10607 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10608 script_object = Handle<Object>(script);
10609 }
10610
10611 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10612 } else {
10613 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10614 // and we check it in this function.
10615 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010616
10617 return Heap::undefined_value();
10618}
10619
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010620
10621// In a code of a parent function replaces original function as embedded object
10622// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010623static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010624 ASSERT(args.length() == 3);
10625 HandleScope scope;
10626
10627 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10628 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10629 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10630
10631 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10632 subst_wrapper);
10633
10634 return Heap::undefined_value();
10635}
10636
10637
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010638// Updates positions of a shared function info (first parameter) according
10639// to script source change. Text change is described in second parameter as
10640// array of groups of 3 numbers:
10641// (change_begin, change_end, change_end_new_position).
10642// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010643static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010644 ASSERT(args.length() == 2);
10645 HandleScope scope;
10646 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10647 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10648
ager@chromium.orgac091b72010-05-05 07:34:42 +000010649 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010650}
10651
10652
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010653// For array of SharedFunctionInfo's (each wrapped in JSValue)
10654// checks that none of them have activations on stacks (of any thread).
10655// Returns array of the same length with corresponding results of
10656// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010657static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010658 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010659 HandleScope scope;
10660 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010661 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010662
ager@chromium.org357bf652010-04-12 11:30:10 +000010663 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010664}
10665
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010666// Compares 2 strings line-by-line, then token-wise and returns diff in form
10667// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
10668// of diff chunks.
10669static MaybeObject* Runtime_LiveEditCompareStrings(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010670 ASSERT(args.length() == 2);
10671 HandleScope scope;
10672 CONVERT_ARG_CHECKED(String, s1, 0);
10673 CONVERT_ARG_CHECKED(String, s2, 1);
10674
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010675 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010676}
10677
10678
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010679
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010680// A testing entry. Returns statement position which is the closest to
10681// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010682static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010683 ASSERT(args.length() == 2);
10684 HandleScope scope;
10685 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10686 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10687
10688 Handle<Code> code(function->code());
10689
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010690 if (code->kind() != Code::FUNCTION &&
10691 code->kind() != Code::OPTIMIZED_FUNCTION) {
10692 return Heap::undefined_value();
10693 }
10694
10695 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010696 int closest_pc = 0;
10697 int distance = kMaxInt;
10698 while (!it.done()) {
10699 int statement_position = static_cast<int>(it.rinfo()->data());
10700 // Check if this break point is closer that what was previously found.
10701 if (source_position <= statement_position &&
10702 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010703 closest_pc =
10704 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010705 distance = statement_position - source_position;
10706 // Check whether we can't get any closer.
10707 if (distance == 0) break;
10708 }
10709 it.next();
10710 }
10711
10712 return Smi::FromInt(closest_pc);
10713}
10714
10715
ager@chromium.org357bf652010-04-12 11:30:10 +000010716// Calls specified function with or without entering the debugger.
10717// This is used in unit tests to run code as if debugger is entered or simply
10718// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010719static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010720 ASSERT(args.length() == 2);
10721 HandleScope scope;
10722 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10723 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10724
10725 Handle<Object> result;
10726 bool pending_exception;
10727 {
10728 if (without_debugger) {
10729 result = Execution::Call(function, Top::global(), 0, NULL,
10730 &pending_exception);
10731 } else {
10732 EnterDebugger enter_debugger;
10733 result = Execution::Call(function, Top::global(), 0, NULL,
10734 &pending_exception);
10735 }
10736 }
10737 if (!pending_exception) {
10738 return *result;
10739 } else {
10740 return Failure::Exception();
10741 }
10742}
10743
10744
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010745// Sets a v8 flag.
10746static MaybeObject* Runtime_SetFlags(Arguments args) {
10747 CONVERT_CHECKED(String, arg, args[0]);
10748 SmartPointer<char> flags =
10749 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
10750 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
10751 return Heap::undefined_value();
10752}
10753
10754
10755// Performs a GC.
10756// Presently, it only does a full GC.
10757static MaybeObject* Runtime_CollectGarbage(Arguments args) {
10758 Heap::CollectAllGarbage(true);
10759 return Heap::undefined_value();
10760}
10761
10762
10763// Gets the current heap usage.
10764static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
10765 int usage = static_cast<int>(Heap::SizeOfObjects());
10766 if (!Smi::IsValid(usage)) {
10767 return *Factory::NewNumberFromInt(usage);
10768 }
10769 return Smi::FromInt(usage);
10770}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010771#endif // ENABLE_DEBUGGER_SUPPORT
10772
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010773
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010774#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org303ada72010-10-27 09:33:13 +000010775static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010776 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010777 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010778
10779 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010780 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10781 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010782 return Heap::undefined_value();
10783}
10784
10785
lrn@chromium.org303ada72010-10-27 09:33:13 +000010786static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010787 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010788 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010789
10790 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010791 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10792 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010793 return Heap::undefined_value();
10794}
10795
10796#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010797
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010798// Finds the script object from the script data. NOTE: This operation uses
10799// heap traversal to find the function generated for the source position
10800// for the requested break point. For lazily compiled functions several heap
10801// traversals might be required rendering this operation as a rather slow
10802// operation. However for setting break points which is normally done through
10803// some kind of user interaction the performance is not crucial.
10804static Handle<Object> Runtime_GetScriptFromScriptName(
10805 Handle<String> script_name) {
10806 // Scan the heap for Script objects to find the script with the requested
10807 // script data.
10808 Handle<Script> script;
10809 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010810 HeapObject* obj = NULL;
10811 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010812 // If a script is found check if it has the script data requested.
10813 if (obj->IsScript()) {
10814 if (Script::cast(obj)->name()->IsString()) {
10815 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
10816 script = Handle<Script>(Script::cast(obj));
10817 }
10818 }
10819 }
10820 }
10821
10822 // If no script with the requested script data is found return undefined.
10823 if (script.is_null()) return Factory::undefined_value();
10824
10825 // Return the script found.
10826 return GetScriptWrapper(script);
10827}
10828
10829
10830// Get the script object from script data. NOTE: Regarding performance
10831// see the NOTE for GetScriptFromScriptData.
10832// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000010833static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010834 HandleScope scope;
10835
10836 ASSERT(args.length() == 1);
10837
10838 CONVERT_CHECKED(String, script_name, args[0]);
10839
10840 // Find the requested script.
10841 Handle<Object> result =
10842 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10843 return *result;
10844}
10845
10846
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010847// Determines whether the given stack frame should be displayed in
10848// a stack trace. The caller is the error constructor that asked
10849// for the stack trace to be collected. The first time a construct
10850// call to this function is encountered it is skipped. The seen_caller
10851// in/out parameter is used to remember if the caller has been seen
10852// yet.
10853static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10854 bool* seen_caller) {
10855 // Only display JS frames.
10856 if (!raw_frame->is_java_script())
10857 return false;
10858 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10859 Object* raw_fun = frame->function();
10860 // Not sure when this can happen but skip it just in case.
10861 if (!raw_fun->IsJSFunction())
10862 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010863 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010864 *seen_caller = true;
10865 return false;
10866 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010867 // Skip all frames until we've seen the caller. Also, skip the most
10868 // obvious builtin calls. Some builtin calls (such as Number.ADD
10869 // which is invoked using 'call') are very difficult to recognize
10870 // so we're leaving them in for now.
10871 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010872}
10873
10874
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010875// Collect the raw data for a stack trace. Returns an array of 4
10876// element segments each containing a receiver, function, code and
10877// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010878static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010879 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010880 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010881 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10882
10883 HandleScope scope;
10884
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010885 limit = Max(limit, 0); // Ensure that limit is not negative.
10886 int initial_size = Min(limit, 10);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010887 Handle<JSArray> result = Factory::NewJSArray(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010888
10889 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010890 // If the caller parameter is a function we skip frames until we're
10891 // under it before starting to collect.
10892 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010893 int cursor = 0;
10894 int frames_seen = 0;
10895 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010896 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010897 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010898 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010899 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010900 List<FrameSummary> frames(3); // Max 2 levels of inlining.
10901 frame->Summarize(&frames);
10902 for (int i = frames.length() - 1; i >= 0; i--) {
10903 Handle<Object> recv = frames[i].receiver();
10904 Handle<JSFunction> fun = frames[i].function();
10905 Handle<Code> code = frames[i].code();
10906 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
10907 FixedArray* elements = FixedArray::cast(result->elements());
10908 if (cursor + 3 < elements->length()) {
10909 elements->set(cursor++, *recv);
10910 elements->set(cursor++, *fun);
10911 elements->set(cursor++, *code);
10912 elements->set(cursor++, *offset);
10913 } else {
10914 SetElement(result, cursor++, recv);
10915 SetElement(result, cursor++, fun);
10916 SetElement(result, cursor++, code);
10917 SetElement(result, cursor++, offset);
10918 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010919 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010920 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010921 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010922 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010923
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010924 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010925 return *result;
10926}
10927
10928
ager@chromium.org3811b432009-10-28 14:53:37 +000010929// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010930static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010931 ASSERT_EQ(args.length(), 0);
10932
10933 NoHandleAllocation ha;
10934
10935 const char* version_string = v8::V8::GetVersion();
10936
10937 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10938}
10939
10940
lrn@chromium.org303ada72010-10-27 09:33:13 +000010941static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010942 ASSERT(args.length() == 2);
10943 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10944 Smi::cast(args[1])->value());
10945 Top::PrintStack();
10946 OS::Abort();
10947 UNREACHABLE();
10948 return NULL;
10949}
10950
10951
lrn@chromium.org303ada72010-10-27 09:33:13 +000010952static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010953 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010954 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010955 Object* key = args[1];
10956
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010957 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010958 Object* o = cache->get(finger_index);
10959 if (o == key) {
10960 // The fastest case: hit the same place again.
10961 return cache->get(finger_index + 1);
10962 }
10963
10964 for (int i = finger_index - 2;
10965 i >= JSFunctionResultCache::kEntriesIndex;
10966 i -= 2) {
10967 o = cache->get(i);
10968 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010969 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010970 return cache->get(i + 1);
10971 }
10972 }
10973
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010974 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010975 ASSERT(size <= cache->length());
10976
10977 for (int i = size - 2; i > finger_index; i -= 2) {
10978 o = cache->get(i);
10979 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010980 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010981 return cache->get(i + 1);
10982 }
10983 }
10984
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010985 // There is no value in the cache. Invoke the function and cache result.
10986 HandleScope scope;
10987
10988 Handle<JSFunctionResultCache> cache_handle(cache);
10989 Handle<Object> key_handle(key);
10990 Handle<Object> value;
10991 {
10992 Handle<JSFunction> factory(JSFunction::cast(
10993 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
10994 // TODO(antonm): consider passing a receiver when constructing a cache.
10995 Handle<Object> receiver(Top::global_context()->global());
10996 // This handle is nor shared, nor used later, so it's safe.
10997 Object** argv[] = { key_handle.location() };
10998 bool pending_exception = false;
10999 value = Execution::Call(factory,
11000 receiver,
11001 1,
11002 argv,
11003 &pending_exception);
11004 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011005 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011006
11007#ifdef DEBUG
11008 cache_handle->JSFunctionResultCacheVerify();
11009#endif
11010
11011 // Function invocation may have cleared the cache. Reread all the data.
11012 finger_index = cache_handle->finger_index();
11013 size = cache_handle->size();
11014
11015 // If we have spare room, put new data into it, otherwise evict post finger
11016 // entry which is likely to be the least recently used.
11017 int index = -1;
11018 if (size < cache_handle->length()) {
11019 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11020 index = size;
11021 } else {
11022 index = finger_index + JSFunctionResultCache::kEntrySize;
11023 if (index == cache_handle->length()) {
11024 index = JSFunctionResultCache::kEntriesIndex;
11025 }
11026 }
11027
11028 ASSERT(index % 2 == 0);
11029 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11030 ASSERT(index < cache_handle->length());
11031
11032 cache_handle->set(index, *key_handle);
11033 cache_handle->set(index + 1, *value);
11034 cache_handle->set_finger_index(index);
11035
11036#ifdef DEBUG
11037 cache_handle->JSFunctionResultCacheVerify();
11038#endif
11039
11040 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011041}
11042
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011043
11044static MaybeObject* Runtime_NewMessageObject(Arguments args) {
11045 HandleScope scope;
11046 CONVERT_ARG_CHECKED(String, type, 0);
11047 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
11048 return *Factory::NewJSMessageObject(type,
11049 arguments,
11050 0,
11051 0,
11052 Factory::undefined_value(),
11053 Factory::undefined_value(),
11054 Factory::undefined_value());
11055}
11056
11057
11058static MaybeObject* Runtime_MessageGetType(Arguments args) {
11059 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11060 return message->type();
11061}
11062
11063
11064static MaybeObject* Runtime_MessageGetArguments(Arguments args) {
11065 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11066 return message->arguments();
11067}
11068
11069
11070static MaybeObject* Runtime_MessageGetStartPosition(Arguments args) {
11071 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11072 return Smi::FromInt(message->start_position());
11073}
11074
11075
11076static MaybeObject* Runtime_MessageGetScript(Arguments args) {
11077 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11078 return message->script();
11079}
11080
11081
kasper.lund44510672008-07-25 07:37:58 +000011082#ifdef DEBUG
11083// ListNatives is ONLY used by the fuzz-natives.js in debug mode
11084// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011085static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000011086 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011087 HandleScope scope;
11088 Handle<JSArray> result = Factory::NewJSArray(0);
11089 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011090 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011091#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011092 { \
11093 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011094 Handle<String> name; \
11095 /* Inline runtime functions have an underscore in front of the name. */ \
11096 if (inline_runtime_functions) { \
11097 name = Factory::NewStringFromAscii( \
11098 Vector<const char>("_" #Name, StrLength("_" #Name))); \
11099 } else { \
11100 name = Factory::NewStringFromAscii( \
11101 Vector<const char>(#Name, StrLength(#Name))); \
11102 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011103 Handle<JSArray> pair = Factory::NewJSArray(0); \
11104 SetElement(pair, 0, name); \
11105 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
11106 SetElement(result, index++, pair); \
11107 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011108 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011109 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011110 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011111 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011112 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011113#undef ADD_ENTRY
11114 return *result;
11115}
kasper.lund44510672008-07-25 07:37:58 +000011116#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011117
11118
lrn@chromium.org303ada72010-10-27 09:33:13 +000011119static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011120 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011121 CONVERT_CHECKED(String, format, args[0]);
11122 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011123 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011124 Logger::LogRuntime(chars, elms);
11125 return Heap::undefined_value();
11126}
11127
11128
lrn@chromium.org303ada72010-10-27 09:33:13 +000011129static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011130 UNREACHABLE(); // implemented as macro in the parser
11131 return NULL;
11132}
11133
11134
11135// ----------------------------------------------------------------------------
11136// Implementation of Runtime
11137
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011138#define F(name, number_of_args, result_size) \
11139 { Runtime::k##name, Runtime::RUNTIME, #name, \
11140 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011141
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011142
11143#define I(name, number_of_args, result_size) \
11144 { Runtime::kInline##name, Runtime::INLINE, \
11145 "_" #name, NULL, number_of_args, result_size },
11146
11147Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011148 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011149 INLINE_FUNCTION_LIST(I)
11150 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011151};
11152
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011153
lrn@chromium.org303ada72010-10-27 09:33:13 +000011154MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011155 ASSERT(dictionary != NULL);
11156 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11157 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011158 Object* name_symbol;
11159 { MaybeObject* maybe_name_symbol =
11160 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
11161 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11162 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011163 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011164 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11165 String::cast(name_symbol),
11166 Smi::FromInt(i),
11167 PropertyDetails(NONE, NORMAL));
11168 if (!maybe_dictionary->ToObject(&dictionary)) {
11169 // Non-recoverable failure. Calling code must restart heap
11170 // initialization.
11171 return maybe_dictionary;
11172 }
11173 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011174 }
11175 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011176}
11177
11178
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011179Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11180 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
11181 if (entry != kNotFound) {
11182 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
11183 int function_index = Smi::cast(smi_index)->value();
11184 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011185 }
11186 return NULL;
11187}
11188
11189
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011190Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
11191 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11192}
11193
11194
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011195void Runtime::PerformGC(Object* result) {
11196 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011197 if (failure->IsRetryAfterGC()) {
11198 // Try to do a garbage collection; ignore it if it fails. The C
11199 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000011200 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011201 } else {
11202 // Handle last resort GC and make sure to allow future allocations
11203 // to grow the heap without causing GCs (if possible).
11204 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000011205 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011206 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011207}
11208
11209
11210} } // namespace v8::internal