blob: 4e7a31c807015ca7bfbc2016f062f986474dcc58 [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
ager@chromium.org5c838252010-02-19 08:53:10 +00003716 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3717}
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;
3917 ASSERT(args.length() == 2);
3918
3919 CONVERT_CHECKED(JSObject, object, args[0]);
3920 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003921 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003922}
3923
3924
ager@chromium.org9085a012009-05-11 19:22:57 +00003925static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3926 Handle<String> key) {
3927 if (object->HasLocalProperty(*key)) return Heap::true_value();
3928 // Handle hidden prototypes. If there's a hidden prototype above this thing
3929 // then we have to check it for properties, because they are supposed to
3930 // look like they are on this object.
3931 Handle<Object> proto(object->GetPrototype());
3932 if (proto->IsJSObject() &&
3933 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3934 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3935 }
3936 return Heap::false_value();
3937}
3938
3939
lrn@chromium.org303ada72010-10-27 09:33:13 +00003940static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003941 NoHandleAllocation ha;
3942 ASSERT(args.length() == 2);
3943 CONVERT_CHECKED(String, key, args[1]);
3944
ager@chromium.org9085a012009-05-11 19:22:57 +00003945 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003946 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003947 if (obj->IsJSObject()) {
3948 JSObject* object = JSObject::cast(obj);
3949 // Fast case - no interceptors.
3950 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3951 // Slow case. Either it's not there or we have an interceptor. We should
3952 // have handles for this kind of deal.
3953 HandleScope scope;
3954 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3955 Handle<String>(key));
3956 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003957 // Well, there is one exception: Handle [] on strings.
3958 uint32_t index;
3959 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003960 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003961 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003962 return Heap::true_value();
3963 }
3964 }
3965 return Heap::false_value();
3966}
3967
3968
lrn@chromium.org303ada72010-10-27 09:33:13 +00003969static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003970 NoHandleAllocation na;
3971 ASSERT(args.length() == 2);
3972
3973 // Only JS objects can have properties.
3974 if (args[0]->IsJSObject()) {
3975 JSObject* object = JSObject::cast(args[0]);
3976 CONVERT_CHECKED(String, key, args[1]);
3977 if (object->HasProperty(key)) return Heap::true_value();
3978 }
3979 return Heap::false_value();
3980}
3981
3982
lrn@chromium.org303ada72010-10-27 09:33:13 +00003983static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003984 NoHandleAllocation na;
3985 ASSERT(args.length() == 2);
3986
3987 // Only JS objects can have elements.
3988 if (args[0]->IsJSObject()) {
3989 JSObject* object = JSObject::cast(args[0]);
3990 CONVERT_CHECKED(Smi, index_obj, args[1]);
3991 uint32_t index = index_obj->value();
3992 if (object->HasElement(index)) return Heap::true_value();
3993 }
3994 return Heap::false_value();
3995}
3996
3997
lrn@chromium.org303ada72010-10-27 09:33:13 +00003998static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003999 NoHandleAllocation ha;
4000 ASSERT(args.length() == 2);
4001
4002 CONVERT_CHECKED(JSObject, object, args[0]);
4003 CONVERT_CHECKED(String, key, args[1]);
4004
4005 uint32_t index;
4006 if (key->AsArrayIndex(&index)) {
4007 return Heap::ToBoolean(object->HasElement(index));
4008 }
4009
ager@chromium.org870a0b62008-11-04 11:43:05 +00004010 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
4011 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004012}
4013
4014
lrn@chromium.org303ada72010-10-27 09:33:13 +00004015static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016 HandleScope scope;
4017 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004018 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 return *GetKeysFor(object);
4020}
4021
4022
4023// Returns either a FixedArray as Runtime_GetPropertyNames,
4024// or, if the given object has an enum cache that contains
4025// all enumerable properties of the object and its prototypes
4026// have none, the map of the object. This is used to speed up
4027// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004028static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 ASSERT(args.length() == 1);
4030
4031 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4032
4033 if (raw_object->IsSimpleEnum()) return raw_object->map();
4034
4035 HandleScope scope;
4036 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004037 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4038 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004039
4040 // Test again, since cache may have been built by preceding call.
4041 if (object->IsSimpleEnum()) return object->map();
4042
4043 return *content;
4044}
4045
4046
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004047// Find the length of the prototype chain that is to to handled as one. If a
4048// prototype object is hidden it is to be viewed as part of the the object it
4049// is prototype for.
4050static int LocalPrototypeChainLength(JSObject* obj) {
4051 int count = 1;
4052 Object* proto = obj->GetPrototype();
4053 while (proto->IsJSObject() &&
4054 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4055 count++;
4056 proto = JSObject::cast(proto)->GetPrototype();
4057 }
4058 return count;
4059}
4060
4061
4062// Return the names of the local named properties.
4063// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004064static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004065 HandleScope scope;
4066 ASSERT(args.length() == 1);
4067 if (!args[0]->IsJSObject()) {
4068 return Heap::undefined_value();
4069 }
4070 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4071
4072 // Skip the global proxy as it has no properties and always delegates to the
4073 // real global object.
4074 if (obj->IsJSGlobalProxy()) {
4075 // Only collect names if access is permitted.
4076 if (obj->IsAccessCheckNeeded() &&
4077 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
4078 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4079 return *Factory::NewJSArray(0);
4080 }
4081 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4082 }
4083
4084 // Find the number of objects making up this.
4085 int length = LocalPrototypeChainLength(*obj);
4086
4087 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004088 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004089 int total_property_count = 0;
4090 Handle<JSObject> jsproto = obj;
4091 for (int i = 0; i < length; i++) {
4092 // Only collect names if access is permitted.
4093 if (jsproto->IsAccessCheckNeeded() &&
4094 !Top::MayNamedAccess(*jsproto,
4095 Heap::undefined_value(),
4096 v8::ACCESS_KEYS)) {
4097 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4098 return *Factory::NewJSArray(0);
4099 }
4100 int n;
4101 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4102 local_property_count[i] = n;
4103 total_property_count += n;
4104 if (i < length - 1) {
4105 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4106 }
4107 }
4108
4109 // Allocate an array with storage for all the property names.
4110 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
4111
4112 // Get the property names.
4113 jsproto = obj;
4114 int proto_with_hidden_properties = 0;
4115 for (int i = 0; i < length; i++) {
4116 jsproto->GetLocalPropertyNames(*names,
4117 i == 0 ? 0 : local_property_count[i - 1]);
4118 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4119 proto_with_hidden_properties++;
4120 }
4121 if (i < length - 1) {
4122 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4123 }
4124 }
4125
4126 // Filter out name of hidden propeties object.
4127 if (proto_with_hidden_properties > 0) {
4128 Handle<FixedArray> old_names = names;
4129 names = Factory::NewFixedArray(
4130 names->length() - proto_with_hidden_properties);
4131 int dest_pos = 0;
4132 for (int i = 0; i < total_property_count; i++) {
4133 Object* name = old_names->get(i);
4134 if (name == Heap::hidden_symbol()) {
4135 continue;
4136 }
4137 names->set(dest_pos++, name);
4138 }
4139 }
4140
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004141 return *Factory::NewJSArrayWithElements(names);
4142}
4143
4144
4145// Return the names of the local indexed properties.
4146// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004147static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004148 HandleScope scope;
4149 ASSERT(args.length() == 1);
4150 if (!args[0]->IsJSObject()) {
4151 return Heap::undefined_value();
4152 }
4153 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4154
4155 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4156 Handle<FixedArray> names = Factory::NewFixedArray(n);
4157 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4158 return *Factory::NewJSArrayWithElements(names);
4159}
4160
4161
4162// Return information on whether an object has a named or indexed interceptor.
4163// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004164static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004165 HandleScope scope;
4166 ASSERT(args.length() == 1);
4167 if (!args[0]->IsJSObject()) {
4168 return Smi::FromInt(0);
4169 }
4170 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4171
4172 int result = 0;
4173 if (obj->HasNamedInterceptor()) result |= 2;
4174 if (obj->HasIndexedInterceptor()) result |= 1;
4175
4176 return Smi::FromInt(result);
4177}
4178
4179
4180// Return property names from named interceptor.
4181// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004182static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004183 HandleScope scope;
4184 ASSERT(args.length() == 1);
4185 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4186
4187 if (obj->HasNamedInterceptor()) {
4188 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4189 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4190 }
4191 return Heap::undefined_value();
4192}
4193
4194
4195// Return element names from indexed interceptor.
4196// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004197static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004198 HandleScope scope;
4199 ASSERT(args.length() == 1);
4200 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4201
4202 if (obj->HasIndexedInterceptor()) {
4203 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4204 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4205 }
4206 return Heap::undefined_value();
4207}
4208
4209
lrn@chromium.org303ada72010-10-27 09:33:13 +00004210static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004211 ASSERT_EQ(args.length(), 1);
4212 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4213 HandleScope scope;
4214 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004215
4216 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004217 // Do access checks before going to the global object.
4218 if (object->IsAccessCheckNeeded() &&
4219 !Top::MayNamedAccess(*object, Heap::undefined_value(),
4220 v8::ACCESS_KEYS)) {
4221 Top::ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4222 return *Factory::NewJSArray(0);
4223 }
4224
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004225 Handle<Object> proto(object->GetPrototype());
4226 // If proxy is detached we simply return an empty array.
4227 if (proto->IsNull()) return *Factory::NewJSArray(0);
4228 object = Handle<JSObject>::cast(proto);
4229 }
4230
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004231 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4232 LOCAL_ONLY);
4233 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4234 // property array and since the result is mutable we have to create
4235 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004236 int length = contents->length();
4237 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4238 for (int i = 0; i < length; i++) {
4239 Object* entry = contents->get(i);
4240 if (entry->IsString()) {
4241 copy->set(i, entry);
4242 } else {
4243 ASSERT(entry->IsNumber());
4244 HandleScope scope;
4245 Handle<Object> entry_handle(entry);
4246 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4247 copy->set(i, *entry_str);
4248 }
4249 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004250 return *Factory::NewJSArrayWithElements(copy);
4251}
4252
4253
lrn@chromium.org303ada72010-10-27 09:33:13 +00004254static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004255 NoHandleAllocation ha;
4256 ASSERT(args.length() == 1);
4257
4258 // Compute the frame holding the arguments.
4259 JavaScriptFrameIterator it;
4260 it.AdvanceToArgumentsFrame();
4261 JavaScriptFrame* frame = it.frame();
4262
4263 // Get the actual number of provided arguments.
4264 const uint32_t n = frame->GetProvidedParametersCount();
4265
4266 // Try to convert the key to an index. If successful and within
4267 // index return the the argument from the frame.
4268 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004269 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004270 return frame->GetParameter(index);
4271 }
4272
4273 // Convert the key to a string.
4274 HandleScope scope;
4275 bool exception = false;
4276 Handle<Object> converted =
4277 Execution::ToString(args.at<Object>(0), &exception);
4278 if (exception) return Failure::Exception();
4279 Handle<String> key = Handle<String>::cast(converted);
4280
4281 // Try to convert the string key into an array index.
4282 if (key->AsArrayIndex(&index)) {
4283 if (index < n) {
4284 return frame->GetParameter(index);
4285 } else {
4286 return Top::initial_object_prototype()->GetElement(index);
4287 }
4288 }
4289
4290 // Handle special arguments properties.
4291 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4292 if (key->Equals(Heap::callee_symbol())) return frame->function();
4293
4294 // Lookup in the initial Object.prototype object.
4295 return Top::initial_object_prototype()->GetProperty(*key);
4296}
4297
4298
lrn@chromium.org303ada72010-10-27 09:33:13 +00004299static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004300 HandleScope scope;
4301
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004302 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004303 Handle<Object> object = args.at<Object>(0);
4304 if (object->IsJSObject()) {
4305 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004306 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004307 MaybeObject* ok = js_object->TransformToFastProperties(0);
4308 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004309 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004310 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004311 return *object;
4312}
4313
4314
lrn@chromium.org303ada72010-10-27 09:33:13 +00004315static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004316 HandleScope scope;
4317
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004318 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004319 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004320 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004321 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004322 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004323 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004324 return *object;
4325}
4326
4327
lrn@chromium.org303ada72010-10-27 09:33:13 +00004328static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004329 NoHandleAllocation ha;
4330 ASSERT(args.length() == 1);
4331
4332 return args[0]->ToBoolean();
4333}
4334
4335
4336// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4337// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004338static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004339 NoHandleAllocation ha;
4340
4341 Object* obj = args[0];
4342 if (obj->IsNumber()) return Heap::number_symbol();
4343 HeapObject* heap_obj = HeapObject::cast(obj);
4344
4345 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004346 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004347
4348 InstanceType instance_type = heap_obj->map()->instance_type();
4349 if (instance_type < FIRST_NONSTRING_TYPE) {
4350 return Heap::string_symbol();
4351 }
4352
4353 switch (instance_type) {
4354 case ODDBALL_TYPE:
4355 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4356 return Heap::boolean_symbol();
4357 }
4358 if (heap_obj->IsNull()) {
4359 return Heap::object_symbol();
4360 }
4361 ASSERT(heap_obj->IsUndefined());
4362 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004363 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004364 return Heap::function_symbol();
4365 default:
4366 // For any kind of object not handled above, the spec rule for
4367 // host objects gives that it is okay to return "object"
4368 return Heap::object_symbol();
4369 }
4370}
4371
4372
lrn@chromium.org25156de2010-04-06 13:10:27 +00004373static bool AreDigits(const char*s, int from, int to) {
4374 for (int i = from; i < to; i++) {
4375 if (s[i] < '0' || s[i] > '9') return false;
4376 }
4377
4378 return true;
4379}
4380
4381
4382static int ParseDecimalInteger(const char*s, int from, int to) {
4383 ASSERT(to - from < 10); // Overflow is not possible.
4384 ASSERT(from < to);
4385 int d = s[from] - '0';
4386
4387 for (int i = from + 1; i < to; i++) {
4388 d = 10 * d + (s[i] - '0');
4389 }
4390
4391 return d;
4392}
4393
4394
lrn@chromium.org303ada72010-10-27 09:33:13 +00004395static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004396 NoHandleAllocation ha;
4397 ASSERT(args.length() == 1);
4398 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004399 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004400
4401 // Fast case: short integer or some sorts of junk values.
4402 int len = subject->length();
4403 if (subject->IsSeqAsciiString()) {
4404 if (len == 0) return Smi::FromInt(0);
4405
4406 char const* data = SeqAsciiString::cast(subject)->GetChars();
4407 bool minus = (data[0] == '-');
4408 int start_pos = (minus ? 1 : 0);
4409
4410 if (start_pos == len) {
4411 return Heap::nan_value();
4412 } else if (data[start_pos] > '9') {
4413 // Fast check for a junk value. A valid string may start from a
4414 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4415 // the 'I' character ('Infinity'). All of that have codes not greater than
4416 // '9' except 'I'.
4417 if (data[start_pos] != 'I') {
4418 return Heap::nan_value();
4419 }
4420 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4421 // The maximal/minimal smi has 10 digits. If the string has less digits we
4422 // know it will fit into the smi-data type.
4423 int d = ParseDecimalInteger(data, start_pos, len);
4424 if (minus) {
4425 if (d == 0) return Heap::minus_zero_value();
4426 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004427 } else if (!subject->HasHashCode() &&
4428 len <= String::kMaxArrayIndexSize &&
4429 (len == 1 || data[0] != '0')) {
4430 // String hash is not calculated yet but all the data are present.
4431 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004432 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004433#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004434 subject->Hash(); // Force hash calculation.
4435 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4436 static_cast<int>(hash));
4437#endif
4438 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004439 }
4440 return Smi::FromInt(d);
4441 }
4442 }
4443
4444 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004445 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4446}
4447
4448
lrn@chromium.org303ada72010-10-27 09:33:13 +00004449static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004450 NoHandleAllocation ha;
4451 ASSERT(args.length() == 1);
4452
4453 CONVERT_CHECKED(JSArray, codes, args[0]);
4454 int length = Smi::cast(codes->length())->value();
4455
4456 // Check if the string can be ASCII.
4457 int i;
4458 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004459 Object* element;
4460 { MaybeObject* maybe_element = codes->GetElement(i);
4461 // We probably can't get an exception here, but just in order to enforce
4462 // the checking of inputs in the runtime calls we check here.
4463 if (!maybe_element->ToObject(&element)) return maybe_element;
4464 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004465 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4466 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4467 break;
4468 }
4469
lrn@chromium.org303ada72010-10-27 09:33:13 +00004470 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004472 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004473 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004474 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004475 }
4476
lrn@chromium.org303ada72010-10-27 09:33:13 +00004477 Object* object = NULL;
4478 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004479 String* result = String::cast(object);
4480 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004481 Object* element;
4482 { MaybeObject* maybe_element = codes->GetElement(i);
4483 if (!maybe_element->ToObject(&element)) return maybe_element;
4484 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004485 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004486 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004487 }
4488 return result;
4489}
4490
4491
4492// kNotEscaped is generated by the following:
4493//
4494// #!/bin/perl
4495// for (my $i = 0; $i < 256; $i++) {
4496// print "\n" if $i % 16 == 0;
4497// my $c = chr($i);
4498// my $escaped = 1;
4499// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4500// print $escaped ? "0, " : "1, ";
4501// }
4502
4503
4504static bool IsNotEscaped(uint16_t character) {
4505 // Only for 8 bit characters, the rest are always escaped (in a different way)
4506 ASSERT(character < 256);
4507 static const char kNotEscaped[256] = {
4508 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4509 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4510 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4511 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4512 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4513 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4514 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4515 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4516 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4517 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4518 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 };
4525 return kNotEscaped[character] != 0;
4526}
4527
4528
lrn@chromium.org303ada72010-10-27 09:33:13 +00004529static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004530 const char hex_chars[] = "0123456789ABCDEF";
4531 NoHandleAllocation ha;
4532 ASSERT(args.length() == 1);
4533 CONVERT_CHECKED(String, source, args[0]);
4534
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004535 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004536
4537 int escaped_length = 0;
4538 int length = source->length();
4539 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004540 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004541 buffer->Reset(source);
4542 while (buffer->has_more()) {
4543 uint16_t character = buffer->GetNext();
4544 if (character >= 256) {
4545 escaped_length += 6;
4546 } else if (IsNotEscaped(character)) {
4547 escaped_length++;
4548 } else {
4549 escaped_length += 3;
4550 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004551 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004552 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004553 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004554 Top::context()->mark_out_of_memory();
4555 return Failure::OutOfMemoryException();
4556 }
4557 }
4558 }
4559 // No length change implies no change. Return original string if no change.
4560 if (escaped_length == length) {
4561 return source;
4562 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004563 Object* o;
4564 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4565 if (!maybe_o->ToObject(&o)) return maybe_o;
4566 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004567 String* destination = String::cast(o);
4568 int dest_position = 0;
4569
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004570 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004571 buffer->Rewind();
4572 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004573 uint16_t chr = buffer->GetNext();
4574 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004575 destination->Set(dest_position, '%');
4576 destination->Set(dest_position+1, 'u');
4577 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4578 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4579 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4580 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004581 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004582 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004583 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004584 dest_position++;
4585 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004586 destination->Set(dest_position, '%');
4587 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4588 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004589 dest_position += 3;
4590 }
4591 }
4592 return destination;
4593}
4594
4595
4596static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4597 static const signed char kHexValue['g'] = {
4598 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4599 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4600 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4601 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4602 -1, 10, 11, 12, 13, 14, 15, -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 -1, 10, 11, 12, 13, 14, 15 };
4605
4606 if (character1 > 'f') return -1;
4607 int hi = kHexValue[character1];
4608 if (hi == -1) return -1;
4609 if (character2 > 'f') return -1;
4610 int lo = kHexValue[character2];
4611 if (lo == -1) return -1;
4612 return (hi << 4) + lo;
4613}
4614
4615
ager@chromium.org870a0b62008-11-04 11:43:05 +00004616static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004617 int i,
4618 int length,
4619 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004620 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004621 int32_t hi = 0;
4622 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004623 if (character == '%' &&
4624 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004625 source->Get(i + 1) == 'u' &&
4626 (hi = TwoDigitHex(source->Get(i + 2),
4627 source->Get(i + 3))) != -1 &&
4628 (lo = TwoDigitHex(source->Get(i + 4),
4629 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004630 *step = 6;
4631 return (hi << 8) + lo;
4632 } else if (character == '%' &&
4633 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004634 (lo = TwoDigitHex(source->Get(i + 1),
4635 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004636 *step = 3;
4637 return lo;
4638 } else {
4639 *step = 1;
4640 return character;
4641 }
4642}
4643
4644
lrn@chromium.org303ada72010-10-27 09:33:13 +00004645static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004646 NoHandleAllocation ha;
4647 ASSERT(args.length() == 1);
4648 CONVERT_CHECKED(String, source, args[0]);
4649
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004650 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004651
4652 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004653 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004654
4655 int unescaped_length = 0;
4656 for (int i = 0; i < length; unescaped_length++) {
4657 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004658 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004659 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004660 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004661 i += step;
4662 }
4663
4664 // No length change implies no change. Return original string if no change.
4665 if (unescaped_length == length)
4666 return source;
4667
lrn@chromium.org303ada72010-10-27 09:33:13 +00004668 Object* o;
4669 { MaybeObject* maybe_o = ascii ?
4670 Heap::AllocateRawAsciiString(unescaped_length) :
4671 Heap::AllocateRawTwoByteString(unescaped_length);
4672 if (!maybe_o->ToObject(&o)) return maybe_o;
4673 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004674 String* destination = String::cast(o);
4675
4676 int dest_position = 0;
4677 for (int i = 0; i < length; dest_position++) {
4678 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004679 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004680 i += step;
4681 }
4682 return destination;
4683}
4684
4685
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004686static const unsigned int kQuoteTableLength = 128u;
4687
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004688static const int kJsonQuotesCharactersPerEntry = 8;
4689static const char* const JsonQuotes =
4690 "\\u0000 \\u0001 \\u0002 \\u0003 "
4691 "\\u0004 \\u0005 \\u0006 \\u0007 "
4692 "\\b \\t \\n \\u000b "
4693 "\\f \\r \\u000e \\u000f "
4694 "\\u0010 \\u0011 \\u0012 \\u0013 "
4695 "\\u0014 \\u0015 \\u0016 \\u0017 "
4696 "\\u0018 \\u0019 \\u001a \\u001b "
4697 "\\u001c \\u001d \\u001e \\u001f "
4698 " ! \\\" # "
4699 "$ % & ' "
4700 "( ) * + "
4701 ", - . / "
4702 "0 1 2 3 "
4703 "4 5 6 7 "
4704 "8 9 : ; "
4705 "< = > ? "
4706 "@ A B C "
4707 "D E F G "
4708 "H I J K "
4709 "L M N O "
4710 "P Q R S "
4711 "T U V W "
4712 "X Y Z [ "
4713 "\\\\ ] ^ _ "
4714 "` a b c "
4715 "d e f g "
4716 "h i j k "
4717 "l m n o "
4718 "p q r s "
4719 "t u v w "
4720 "x y z { "
4721 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004722
4723
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004724// For a string that is less than 32k characters it should always be
4725// possible to allocate it in new space.
4726static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4727
4728
4729// Doing JSON quoting cannot make the string more than this many times larger.
4730static const int kJsonQuoteWorstCaseBlowup = 6;
4731
4732
4733// Covers the entire ASCII range (all other characters are unchanged by JSON
4734// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004735static const byte JsonQuoteLengths[kQuoteTableLength] = {
4736 6, 6, 6, 6, 6, 6, 6, 6,
4737 2, 2, 2, 6, 2, 2, 6, 6,
4738 6, 6, 6, 6, 6, 6, 6, 6,
4739 6, 6, 6, 6, 6, 6, 6, 6,
4740 1, 1, 2, 1, 1, 1, 1, 1,
4741 1, 1, 1, 1, 1, 1, 1, 1,
4742 1, 1, 1, 1, 1, 1, 1, 1,
4743 1, 1, 1, 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, 2, 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, 1, 1, 1, 1,
4751 1, 1, 1, 1, 1, 1, 1, 1,
4752};
4753
4754
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004755template <typename StringType>
4756MaybeObject* AllocateRawString(int length);
4757
4758
4759template <>
4760MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4761 return Heap::AllocateRawTwoByteString(length);
4762}
4763
4764
4765template <>
4766MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4767 return Heap::AllocateRawAsciiString(length);
4768}
4769
4770
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004771template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004772static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004773 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004774 const Char* read_cursor = characters.start();
4775 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004776 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004777 int quoted_length = kSpaceForQuotes;
4778 while (read_cursor < end) {
4779 Char c = *(read_cursor++);
4780 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4781 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004782 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004783 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004784 }
4785 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004786 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4787 Object* new_object;
4788 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004789 return new_alloc;
4790 }
4791 StringType* new_string = StringType::cast(new_object);
4792
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004793 Char* write_cursor = reinterpret_cast<Char*>(
4794 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004795 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004796 *(write_cursor++) = '"';
4797
4798 read_cursor = characters.start();
4799 while (read_cursor < end) {
4800 Char c = *(read_cursor++);
4801 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4802 *(write_cursor++) = c;
4803 } else {
4804 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4805 const char* replacement = JsonQuotes +
4806 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4807 for (int i = 0; i < len; i++) {
4808 *write_cursor++ = *replacement++;
4809 }
4810 }
4811 }
4812 *(write_cursor++) = '"';
4813 return new_string;
4814}
4815
4816
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004817template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004818static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4819 int length = characters.length();
4820 Counters::quote_json_char_count.Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004821 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004822 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4823 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004824 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004825 }
4826
4827 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4828 Object* new_object;
4829 if (!new_alloc->ToObject(&new_object)) {
4830 return new_alloc;
4831 }
4832 if (!Heap::new_space()->Contains(new_object)) {
4833 // Even if our string is small enough to fit in new space we still have to
4834 // handle it being allocated in old space as may happen in the third
4835 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4836 // CEntryStub::GenerateCore.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004837 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004838 }
4839 StringType* new_string = StringType::cast(new_object);
4840 ASSERT(Heap::new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004841
4842 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4843 Char* write_cursor = reinterpret_cast<Char*>(
4844 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004845 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004846 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004847
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004848 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004849 const Char* end = read_cursor + length;
4850 while (read_cursor < end) {
4851 Char c = *(read_cursor++);
4852 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4853 *(write_cursor++) = c;
4854 } else {
4855 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4856 const char* replacement = JsonQuotes +
4857 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4858 write_cursor[0] = replacement[0];
4859 if (len > 1) {
4860 write_cursor[1] = replacement[1];
4861 if (len > 2) {
4862 ASSERT(len == 6);
4863 write_cursor[2] = replacement[2];
4864 write_cursor[3] = replacement[3];
4865 write_cursor[4] = replacement[4];
4866 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004867 }
4868 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004869 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004870 }
4871 }
4872 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004873
4874 int final_length = static_cast<int>(
4875 write_cursor - reinterpret_cast<Char*>(
4876 new_string->address() + SeqAsciiString::kHeaderSize));
4877 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4878 final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004879 return new_string;
4880}
4881
4882
4883static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4884 NoHandleAllocation ha;
4885 CONVERT_CHECKED(String, str, args[0]);
4886 if (!str->IsFlat()) {
4887 MaybeObject* try_flatten = str->TryFlatten();
4888 Object* flat;
4889 if (!try_flatten->ToObject(&flat)) {
4890 return try_flatten;
4891 }
4892 str = String::cast(flat);
4893 ASSERT(str->IsFlat());
4894 }
4895 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004896 return QuoteJsonString<uc16, SeqTwoByteString, false>(str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004897 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004898 return QuoteJsonString<char, SeqAsciiString, false>(str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004899 }
4900}
4901
4902
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004903static MaybeObject* Runtime_QuoteJSONStringComma(Arguments args) {
4904 NoHandleAllocation ha;
4905 CONVERT_CHECKED(String, str, args[0]);
4906 if (!str->IsFlat()) {
4907 MaybeObject* try_flatten = str->TryFlatten();
4908 Object* flat;
4909 if (!try_flatten->ToObject(&flat)) {
4910 return try_flatten;
4911 }
4912 str = String::cast(flat);
4913 ASSERT(str->IsFlat());
4914 }
4915 if (str->IsTwoByteRepresentation()) {
4916 return QuoteJsonString<uc16, SeqTwoByteString, true>(str->ToUC16Vector());
4917 } else {
4918 return QuoteJsonString<char, SeqAsciiString, true>(str->ToAsciiVector());
4919 }
4920}
4921
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004922
lrn@chromium.org303ada72010-10-27 09:33:13 +00004923static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004924 NoHandleAllocation ha;
4925
4926 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004927 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004928
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004929 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004930
lrn@chromium.org25156de2010-04-06 13:10:27 +00004931 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4932 double value = StringToInt(s, radix);
4933 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004934}
4935
4936
lrn@chromium.org303ada72010-10-27 09:33:13 +00004937static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004938 NoHandleAllocation ha;
4939 CONVERT_CHECKED(String, str, args[0]);
4940
4941 // ECMA-262 section 15.1.2.3, empty string is NaN
4942 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4943
4944 // Create a number object from the value.
4945 return Heap::NumberFromDouble(value);
4946}
4947
4948
4949static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4950static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4951
4952
4953template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004954MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4955 String* s,
4956 int length,
4957 int input_string_length,
4958 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004959 // We try this twice, once with the assumption that the result is no longer
4960 // than the input and, if that assumption breaks, again with the exact
4961 // length. This may not be pretty, but it is nicer than what was here before
4962 // and I hereby claim my vaffel-is.
4963 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004964 // Allocate the resulting string.
4965 //
4966 // NOTE: This assumes that the upper/lower case of an ascii
4967 // character is also ascii. This is currently the case, but it
4968 // might break in the future if we implement more context and locale
4969 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004970 Object* o;
4971 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4972 ? Heap::AllocateRawAsciiString(length)
4973 : Heap::AllocateRawTwoByteString(length);
4974 if (!maybe_o->ToObject(&o)) return maybe_o;
4975 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004976 String* result = String::cast(o);
4977 bool has_changed_character = false;
4978
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004979 // Convert all characters to upper case, assuming that they will fit
4980 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004981 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004982 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004983 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004984 // We can assume that the string is not empty
4985 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004986 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004987 bool has_next = buffer->has_more();
4988 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004989 int char_length = mapping->get(current, next, chars);
4990 if (char_length == 0) {
4991 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004992 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004993 i++;
4994 } else if (char_length == 1) {
4995 // Common case: converting the letter resulted in one character.
4996 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004997 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004998 has_changed_character = true;
4999 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005000 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005001 // We've assumed that the result would be as long as the
5002 // input but here is a character that converts to several
5003 // characters. No matter, we calculate the exact length
5004 // of the result and try the whole thing again.
5005 //
5006 // Note that this leaves room for optimization. We could just
5007 // memcpy what we already have to the result string. Also,
5008 // the result string is the last object allocated we could
5009 // "realloc" it and probably, in the vast majority of cases,
5010 // extend the existing string to be able to hold the full
5011 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005012 int next_length = 0;
5013 if (has_next) {
5014 next_length = mapping->get(next, 0, chars);
5015 if (next_length == 0) next_length = 1;
5016 }
5017 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005018 while (buffer->has_more()) {
5019 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005020 // NOTE: we use 0 as the next character here because, while
5021 // the next character may affect what a character converts to,
5022 // it does not in any case affect the length of what it convert
5023 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005024 int char_length = mapping->get(current, 0, chars);
5025 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005026 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005027 if (current_length > Smi::kMaxValue) {
5028 Top::context()->mark_out_of_memory();
5029 return Failure::OutOfMemoryException();
5030 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005031 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005032 // Try again with the real length.
5033 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005034 } else {
5035 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005036 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005037 i++;
5038 }
5039 has_changed_character = true;
5040 }
5041 current = next;
5042 }
5043 if (has_changed_character) {
5044 return result;
5045 } else {
5046 // If we didn't actually change anything in doing the conversion
5047 // we simple return the result and let the converted string
5048 // become garbage; there is no reason to keep two identical strings
5049 // alive.
5050 return s;
5051 }
5052}
5053
5054
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005055namespace {
5056
lrn@chromium.org303ada72010-10-27 09:33:13 +00005057static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5058
5059
5060// Given a word and two range boundaries returns a word with high bit
5061// set in every byte iff the corresponding input byte was strictly in
5062// the range (m, n). All the other bits in the result are cleared.
5063// This function is only useful when it can be inlined and the
5064// boundaries are statically known.
5065// Requires: all bytes in the input word and the boundaries must be
5066// ascii (less than 0x7F).
5067static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5068 // Every byte in an ascii string is less than or equal to 0x7F.
5069 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5070 // Use strict inequalities since in edge cases the function could be
5071 // further simplified.
5072 ASSERT(0 < m && m < n && n < 0x7F);
5073 // Has high bit set in every w byte less than n.
5074 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5075 // Has high bit set in every w byte greater than m.
5076 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5077 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5078}
5079
5080
5081enum AsciiCaseConversion {
5082 ASCII_TO_LOWER,
5083 ASCII_TO_UPPER
5084};
5085
5086
5087template <AsciiCaseConversion dir>
5088struct FastAsciiConverter {
5089 static bool Convert(char* dst, char* src, int length) {
5090#ifdef DEBUG
5091 char* saved_dst = dst;
5092 char* saved_src = src;
5093#endif
5094 // We rely on the distance between upper and lower case letters
5095 // being a known power of 2.
5096 ASSERT('a' - 'A' == (1 << 5));
5097 // Boundaries for the range of input characters than require conversion.
5098 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5099 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5100 bool changed = false;
5101 char* const limit = src + length;
5102#ifdef V8_HOST_CAN_READ_UNALIGNED
5103 // Process the prefix of the input that requires no conversion one
5104 // (machine) word at a time.
5105 while (src <= limit - sizeof(uintptr_t)) {
5106 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5107 if (AsciiRangeMask(w, lo, hi) != 0) {
5108 changed = true;
5109 break;
5110 }
5111 *reinterpret_cast<uintptr_t*>(dst) = w;
5112 src += sizeof(uintptr_t);
5113 dst += sizeof(uintptr_t);
5114 }
5115 // Process the remainder of the input performing conversion when
5116 // required one word at a time.
5117 while (src <= limit - sizeof(uintptr_t)) {
5118 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5119 uintptr_t m = AsciiRangeMask(w, lo, hi);
5120 // The mask has high (7th) bit set in every byte that needs
5121 // conversion and we know that the distance between cases is
5122 // 1 << 5.
5123 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5124 src += sizeof(uintptr_t);
5125 dst += sizeof(uintptr_t);
5126 }
5127#endif
5128 // Process the last few bytes of the input (or the whole input if
5129 // unaligned access is not supported).
5130 while (src < limit) {
5131 char c = *src;
5132 if (lo < c && c < hi) {
5133 c ^= (1 << 5);
5134 changed = true;
5135 }
5136 *dst = c;
5137 ++src;
5138 ++dst;
5139 }
5140#ifdef DEBUG
5141 CheckConvert(saved_dst, saved_src, length, changed);
5142#endif
5143 return changed;
5144 }
5145
5146#ifdef DEBUG
5147 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5148 bool expected_changed = false;
5149 for (int i = 0; i < length; i++) {
5150 if (dst[i] == src[i]) continue;
5151 expected_changed = true;
5152 if (dir == ASCII_TO_LOWER) {
5153 ASSERT('A' <= src[i] && src[i] <= 'Z');
5154 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5155 } else {
5156 ASSERT(dir == ASCII_TO_UPPER);
5157 ASSERT('a' <= src[i] && src[i] <= 'z');
5158 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5159 }
5160 }
5161 ASSERT(expected_changed == changed);
5162 }
5163#endif
5164};
5165
5166
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005167struct ToLowerTraits {
5168 typedef unibrow::ToLowercase UnibrowConverter;
5169
lrn@chromium.org303ada72010-10-27 09:33:13 +00005170 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005171};
5172
5173
5174struct ToUpperTraits {
5175 typedef unibrow::ToUppercase UnibrowConverter;
5176
lrn@chromium.org303ada72010-10-27 09:33:13 +00005177 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005178};
5179
5180} // namespace
5181
5182
5183template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005184MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005185 Arguments args,
5186 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005187 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005188 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005189 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005190
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005191 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005192 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005193 if (length == 0) return s;
5194
5195 // Simpler handling of ascii strings.
5196 //
5197 // NOTE: This assumes that the upper/lower case of an ascii
5198 // character is also ascii. This is currently the case, but it
5199 // might break in the future if we implement more context and locale
5200 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005201 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005202 Object* o;
5203 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
5204 if (!maybe_o->ToObject(&o)) return maybe_o;
5205 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005206 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005207 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005208 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005209 return has_changed_character ? result : s;
5210 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005211
lrn@chromium.org303ada72010-10-27 09:33:13 +00005212 Object* answer;
5213 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5214 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5215 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005216 if (answer->IsSmi()) {
5217 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005218 { MaybeObject* maybe_answer =
5219 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5220 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5221 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005222 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005223 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005224}
5225
5226
lrn@chromium.org303ada72010-10-27 09:33:13 +00005227static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005228 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005229}
5230
5231
lrn@chromium.org303ada72010-10-27 09:33:13 +00005232static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005233 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005234}
5235
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005236
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005237static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5238 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5239}
5240
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005241
lrn@chromium.org303ada72010-10-27 09:33:13 +00005242static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005243 NoHandleAllocation ha;
5244 ASSERT(args.length() == 3);
5245
5246 CONVERT_CHECKED(String, s, args[0]);
5247 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5248 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5249
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005250 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005251 int length = s->length();
5252
5253 int left = 0;
5254 if (trimLeft) {
5255 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5256 left++;
5257 }
5258 }
5259
5260 int right = length;
5261 if (trimRight) {
5262 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5263 right--;
5264 }
5265 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005266 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005267}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005268
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005269
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005270template <typename SubjectChar, typename PatternChar>
5271void FindStringIndices(Vector<const SubjectChar> subject,
5272 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005273 ZoneList<int>* indices,
5274 unsigned int limit) {
5275 ASSERT(limit > 0);
5276 // Collect indices of pattern in subject, and the end-of-string index.
5277 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005278 StringSearch<PatternChar, SubjectChar> search(pattern);
5279 int pattern_length = pattern.length();
5280 int index = 0;
5281 while (limit > 0) {
5282 index = search.Search(subject, index);
5283 if (index < 0) return;
5284 indices->Add(index);
5285 index += pattern_length;
5286 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005287 }
5288}
5289
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005290
lrn@chromium.org303ada72010-10-27 09:33:13 +00005291static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005292 ASSERT(args.length() == 3);
5293 HandleScope handle_scope;
5294 CONVERT_ARG_CHECKED(String, subject, 0);
5295 CONVERT_ARG_CHECKED(String, pattern, 1);
5296 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5297
5298 int subject_length = subject->length();
5299 int pattern_length = pattern->length();
5300 RUNTIME_ASSERT(pattern_length > 0);
5301
5302 // The limit can be very large (0xffffffffu), but since the pattern
5303 // isn't empty, we can never create more parts than ~half the length
5304 // of the subject.
5305
5306 if (!subject->IsFlat()) FlattenString(subject);
5307
5308 static const int kMaxInitialListCapacity = 16;
5309
5310 ZoneScope scope(DELETE_ON_EXIT);
5311
5312 // Find (up to limit) indices of separator and end-of-string in subject
5313 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5314 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005315 if (!pattern->IsFlat()) FlattenString(pattern);
5316
5317 // No allocation block.
5318 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005319 AssertNoAllocation nogc;
5320 if (subject->IsAsciiRepresentation()) {
5321 Vector<const char> subject_vector = subject->ToAsciiVector();
5322 if (pattern->IsAsciiRepresentation()) {
5323 FindStringIndices(subject_vector,
5324 pattern->ToAsciiVector(),
5325 &indices,
5326 limit);
5327 } else {
5328 FindStringIndices(subject_vector,
5329 pattern->ToUC16Vector(),
5330 &indices,
5331 limit);
5332 }
5333 } else {
5334 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5335 if (pattern->IsAsciiRepresentation()) {
5336 FindStringIndices(subject_vector,
5337 pattern->ToAsciiVector(),
5338 &indices,
5339 limit);
5340 } else {
5341 FindStringIndices(subject_vector,
5342 pattern->ToUC16Vector(),
5343 &indices,
5344 limit);
5345 }
5346 }
5347 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005348
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005349 if (static_cast<uint32_t>(indices.length()) < limit) {
5350 indices.Add(subject_length);
5351 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005352
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005353 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005354
5355 // Create JSArray of substrings separated by separator.
5356 int part_count = indices.length();
5357
5358 Handle<JSArray> result = Factory::NewJSArray(part_count);
5359 result->set_length(Smi::FromInt(part_count));
5360
5361 ASSERT(result->HasFastElements());
5362
5363 if (part_count == 1 && indices.at(0) == subject_length) {
5364 FixedArray::cast(result->elements())->set(0, *subject);
5365 return *result;
5366 }
5367
5368 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5369 int part_start = 0;
5370 for (int i = 0; i < part_count; i++) {
5371 HandleScope local_loop_handle;
5372 int part_end = indices.at(i);
5373 Handle<String> substring =
5374 Factory::NewSubString(subject, part_start, part_end);
5375 elements->set(i, *substring);
5376 part_start = part_end + pattern_length;
5377 }
5378
5379 return *result;
5380}
5381
5382
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005383// Copies ascii characters to the given fixed array looking up
5384// one-char strings in the cache. Gives up on the first char that is
5385// not in the cache and fills the remainder with smi zeros. Returns
5386// the length of the successfully copied prefix.
5387static int CopyCachedAsciiCharsToArray(const char* chars,
5388 FixedArray* elements,
5389 int length) {
5390 AssertNoAllocation nogc;
5391 FixedArray* ascii_cache = Heap::single_character_string_cache();
5392 Object* undefined = Heap::undefined_value();
5393 int i;
5394 for (i = 0; i < length; ++i) {
5395 Object* value = ascii_cache->get(chars[i]);
5396 if (value == undefined) break;
5397 ASSERT(!Heap::InNewSpace(value));
5398 elements->set(i, value, SKIP_WRITE_BARRIER);
5399 }
5400 if (i < length) {
5401 ASSERT(Smi::FromInt(0) == 0);
5402 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5403 }
5404#ifdef DEBUG
5405 for (int j = 0; j < length; ++j) {
5406 Object* element = elements->get(j);
5407 ASSERT(element == Smi::FromInt(0) ||
5408 (element->IsString() && String::cast(element)->LooksValid()));
5409 }
5410#endif
5411 return i;
5412}
5413
5414
5415// Converts a String to JSArray.
5416// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005417static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005418 HandleScope scope;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005419 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005420 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005421 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005422
5423 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005424 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005425
5426 Handle<FixedArray> elements;
5427 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005428 Object* obj;
5429 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5430 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5431 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005432 elements = Handle<FixedArray>(FixedArray::cast(obj));
5433
5434 Vector<const char> chars = s->ToAsciiVector();
5435 // Note, this will initialize all elements (not only the prefix)
5436 // to prevent GC from seeing partially initialized array.
5437 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5438 *elements,
5439 length);
5440
5441 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005442 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5443 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005444 }
5445 } else {
5446 elements = Factory::NewFixedArray(length);
5447 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005448 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5449 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005450 }
5451 }
5452
5453#ifdef DEBUG
5454 for (int i = 0; i < length; ++i) {
5455 ASSERT(String::cast(elements->get(i))->length() == 1);
5456 }
5457#endif
5458
5459 return *Factory::NewJSArrayWithElements(elements);
5460}
5461
5462
lrn@chromium.org303ada72010-10-27 09:33:13 +00005463static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005464 NoHandleAllocation ha;
5465 ASSERT(args.length() == 1);
5466 CONVERT_CHECKED(String, value, args[0]);
5467 return value->ToObject();
5468}
5469
5470
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005471bool Runtime::IsUpperCaseChar(uint16_t ch) {
5472 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5473 int char_length = to_upper_mapping.get(ch, 0, chars);
5474 return char_length == 0;
5475}
5476
5477
lrn@chromium.org303ada72010-10-27 09:33:13 +00005478static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479 NoHandleAllocation ha;
5480 ASSERT(args.length() == 1);
5481
5482 Object* number = args[0];
5483 RUNTIME_ASSERT(number->IsNumber());
5484
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005485 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005486}
5487
5488
lrn@chromium.org303ada72010-10-27 09:33:13 +00005489static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005490 NoHandleAllocation ha;
5491 ASSERT(args.length() == 1);
5492
5493 Object* number = args[0];
5494 RUNTIME_ASSERT(number->IsNumber());
5495
5496 return Heap::NumberToString(number, false);
5497}
5498
5499
lrn@chromium.org303ada72010-10-27 09:33:13 +00005500static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501 NoHandleAllocation ha;
5502 ASSERT(args.length() == 1);
5503
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005504 CONVERT_DOUBLE_CHECKED(number, args[0]);
5505
5506 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5507 if (number > 0 && number <= Smi::kMaxValue) {
5508 return Smi::FromInt(static_cast<int>(number));
5509 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005510 return Heap::NumberFromDouble(DoubleToInteger(number));
5511}
5512
5513
lrn@chromium.org303ada72010-10-27 09:33:13 +00005514static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005515 NoHandleAllocation ha;
5516 ASSERT(args.length() == 1);
5517
5518 CONVERT_DOUBLE_CHECKED(number, args[0]);
5519
5520 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5521 if (number > 0 && number <= Smi::kMaxValue) {
5522 return Smi::FromInt(static_cast<int>(number));
5523 }
5524
5525 double double_value = DoubleToInteger(number);
5526 // Map both -0 and +0 to +0.
5527 if (double_value == 0) double_value = 0;
5528
5529 return Heap::NumberFromDouble(double_value);
5530}
5531
5532
lrn@chromium.org303ada72010-10-27 09:33:13 +00005533static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005534 NoHandleAllocation ha;
5535 ASSERT(args.length() == 1);
5536
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005537 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005538 return Heap::NumberFromUint32(number);
5539}
5540
5541
lrn@chromium.org303ada72010-10-27 09:33:13 +00005542static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005543 NoHandleAllocation ha;
5544 ASSERT(args.length() == 1);
5545
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005546 CONVERT_DOUBLE_CHECKED(number, args[0]);
5547
5548 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5549 if (number > 0 && number <= Smi::kMaxValue) {
5550 return Smi::FromInt(static_cast<int>(number));
5551 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005552 return Heap::NumberFromInt32(DoubleToInt32(number));
5553}
5554
5555
ager@chromium.org870a0b62008-11-04 11:43:05 +00005556// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5557// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005558static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005559 NoHandleAllocation ha;
5560 ASSERT(args.length() == 1);
5561
5562 Object* obj = args[0];
5563 if (obj->IsSmi()) {
5564 return obj;
5565 }
5566 if (obj->IsHeapNumber()) {
5567 double value = HeapNumber::cast(obj)->value();
5568 int int_value = FastD2I(value);
5569 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5570 return Smi::FromInt(int_value);
5571 }
5572 }
5573 return Heap::nan_value();
5574}
5575
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005576
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005577static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5578 NoHandleAllocation ha;
5579 ASSERT(args.length() == 0);
5580 return Heap::AllocateHeapNumber(0);
5581}
5582
5583
lrn@chromium.org303ada72010-10-27 09:33:13 +00005584static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005585 NoHandleAllocation ha;
5586 ASSERT(args.length() == 2);
5587
5588 CONVERT_DOUBLE_CHECKED(x, args[0]);
5589 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005590 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005591}
5592
5593
lrn@chromium.org303ada72010-10-27 09:33:13 +00005594static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005595 NoHandleAllocation ha;
5596 ASSERT(args.length() == 2);
5597
5598 CONVERT_DOUBLE_CHECKED(x, args[0]);
5599 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005600 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005601}
5602
5603
lrn@chromium.org303ada72010-10-27 09:33:13 +00005604static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005605 NoHandleAllocation ha;
5606 ASSERT(args.length() == 2);
5607
5608 CONVERT_DOUBLE_CHECKED(x, args[0]);
5609 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005610 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005611}
5612
5613
lrn@chromium.org303ada72010-10-27 09:33:13 +00005614static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005615 NoHandleAllocation ha;
5616 ASSERT(args.length() == 1);
5617
5618 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005619 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005620}
5621
5622
lrn@chromium.org303ada72010-10-27 09:33:13 +00005623static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005624 NoHandleAllocation ha;
5625 ASSERT(args.length() == 0);
5626
5627 return Heap::NumberFromDouble(9876543210.0);
5628}
5629
5630
lrn@chromium.org303ada72010-10-27 09:33:13 +00005631static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005632 NoHandleAllocation ha;
5633 ASSERT(args.length() == 2);
5634
5635 CONVERT_DOUBLE_CHECKED(x, args[0]);
5636 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005637 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005638}
5639
5640
lrn@chromium.org303ada72010-10-27 09:33:13 +00005641static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005642 NoHandleAllocation ha;
5643 ASSERT(args.length() == 2);
5644
5645 CONVERT_DOUBLE_CHECKED(x, args[0]);
5646 CONVERT_DOUBLE_CHECKED(y, args[1]);
5647
ager@chromium.org3811b432009-10-28 14:53:37 +00005648 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005649 // NumberFromDouble may return a Smi instead of a Number object
5650 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005651}
5652
5653
lrn@chromium.org303ada72010-10-27 09:33:13 +00005654static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005655 NoHandleAllocation ha;
5656 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005657 CONVERT_CHECKED(String, str1, args[0]);
5658 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005659 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005660 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005661}
5662
5663
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005664template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005665static inline void StringBuilderConcatHelper(String* special,
5666 sinkchar* sink,
5667 FixedArray* fixed_array,
5668 int array_length) {
5669 int position = 0;
5670 for (int i = 0; i < array_length; i++) {
5671 Object* element = fixed_array->get(i);
5672 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005673 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005674 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005675 int pos;
5676 int len;
5677 if (encoded_slice > 0) {
5678 // Position and length encoded in one smi.
5679 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5680 len = StringBuilderSubstringLength::decode(encoded_slice);
5681 } else {
5682 // Position and length encoded in two smis.
5683 Object* obj = fixed_array->get(++i);
5684 ASSERT(obj->IsSmi());
5685 pos = Smi::cast(obj)->value();
5686 len = -encoded_slice;
5687 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005688 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005689 sink + position,
5690 pos,
5691 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005692 position += len;
5693 } else {
5694 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005695 int element_length = string->length();
5696 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005697 position += element_length;
5698 }
5699 }
5700}
5701
5702
lrn@chromium.org303ada72010-10-27 09:33:13 +00005703static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005704 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005705 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005706 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005707 if (!args[1]->IsSmi()) {
5708 Top::context()->mark_out_of_memory();
5709 return Failure::OutOfMemoryException();
5710 }
5711 int array_length = Smi::cast(args[1])->value();
5712 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005713
5714 // This assumption is used by the slice encoding in one or two smis.
5715 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5716
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005717 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005718 if (!array->HasFastElements()) {
5719 return Top::Throw(Heap::illegal_argument_symbol());
5720 }
5721 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005722 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005723 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005724 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005725
5726 if (array_length == 0) {
5727 return Heap::empty_string();
5728 } else if (array_length == 1) {
5729 Object* first = fixed_array->get(0);
5730 if (first->IsString()) return first;
5731 }
5732
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005733 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005734 int position = 0;
5735 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005736 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005737 Object* elt = fixed_array->get(i);
5738 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005739 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005740 int smi_value = Smi::cast(elt)->value();
5741 int pos;
5742 int len;
5743 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005744 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005745 pos = StringBuilderSubstringPosition::decode(smi_value);
5746 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005747 } else {
5748 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005749 len = -smi_value;
5750 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005751 i++;
5752 if (i >= array_length) {
5753 return Top::Throw(Heap::illegal_argument_symbol());
5754 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005755 Object* next_smi = fixed_array->get(i);
5756 if (!next_smi->IsSmi()) {
5757 return Top::Throw(Heap::illegal_argument_symbol());
5758 }
5759 pos = Smi::cast(next_smi)->value();
5760 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005761 return Top::Throw(Heap::illegal_argument_symbol());
5762 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005763 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005764 ASSERT(pos >= 0);
5765 ASSERT(len >= 0);
5766 if (pos > special_length || len > special_length - pos) {
5767 return Top::Throw(Heap::illegal_argument_symbol());
5768 }
5769 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005770 } else if (elt->IsString()) {
5771 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005772 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005773 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005774 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005775 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005776 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005777 } else {
5778 return Top::Throw(Heap::illegal_argument_symbol());
5779 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005780 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005781 Top::context()->mark_out_of_memory();
5782 return Failure::OutOfMemoryException();
5783 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005784 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005785 }
5786
5787 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005788 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005789
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005790 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005791 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5792 if (!maybe_object->ToObject(&object)) return maybe_object;
5793 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005794 SeqAsciiString* answer = SeqAsciiString::cast(object);
5795 StringBuilderConcatHelper(special,
5796 answer->GetChars(),
5797 fixed_array,
5798 array_length);
5799 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005800 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005801 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5802 if (!maybe_object->ToObject(&object)) return maybe_object;
5803 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005804 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5805 StringBuilderConcatHelper(special,
5806 answer->GetChars(),
5807 fixed_array,
5808 array_length);
5809 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005810 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005811}
5812
5813
lrn@chromium.org303ada72010-10-27 09:33:13 +00005814static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005815 NoHandleAllocation ha;
5816 ASSERT(args.length() == 2);
5817
5818 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5819 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5820 return Heap::NumberFromInt32(x | y);
5821}
5822
5823
lrn@chromium.org303ada72010-10-27 09:33:13 +00005824static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005825 NoHandleAllocation ha;
5826 ASSERT(args.length() == 2);
5827
5828 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5829 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5830 return Heap::NumberFromInt32(x & y);
5831}
5832
5833
lrn@chromium.org303ada72010-10-27 09:33:13 +00005834static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005835 NoHandleAllocation ha;
5836 ASSERT(args.length() == 2);
5837
5838 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5839 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5840 return Heap::NumberFromInt32(x ^ y);
5841}
5842
5843
lrn@chromium.org303ada72010-10-27 09:33:13 +00005844static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005845 NoHandleAllocation ha;
5846 ASSERT(args.length() == 1);
5847
5848 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5849 return Heap::NumberFromInt32(~x);
5850}
5851
5852
lrn@chromium.org303ada72010-10-27 09:33:13 +00005853static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005854 NoHandleAllocation ha;
5855 ASSERT(args.length() == 2);
5856
5857 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5858 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5859 return Heap::NumberFromInt32(x << (y & 0x1f));
5860}
5861
5862
lrn@chromium.org303ada72010-10-27 09:33:13 +00005863static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005864 NoHandleAllocation ha;
5865 ASSERT(args.length() == 2);
5866
5867 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5868 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5869 return Heap::NumberFromUint32(x >> (y & 0x1f));
5870}
5871
5872
lrn@chromium.org303ada72010-10-27 09:33:13 +00005873static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005874 NoHandleAllocation ha;
5875 ASSERT(args.length() == 2);
5876
5877 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5878 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5879 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5880}
5881
5882
lrn@chromium.org303ada72010-10-27 09:33:13 +00005883static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005884 NoHandleAllocation ha;
5885 ASSERT(args.length() == 2);
5886
5887 CONVERT_DOUBLE_CHECKED(x, args[0]);
5888 CONVERT_DOUBLE_CHECKED(y, args[1]);
5889 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5890 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5891 if (x == y) return Smi::FromInt(EQUAL);
5892 Object* result;
5893 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5894 result = Smi::FromInt(EQUAL);
5895 } else {
5896 result = Smi::FromInt(NOT_EQUAL);
5897 }
5898 return result;
5899}
5900
5901
lrn@chromium.org303ada72010-10-27 09:33:13 +00005902static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005903 NoHandleAllocation ha;
5904 ASSERT(args.length() == 2);
5905
5906 CONVERT_CHECKED(String, x, args[0]);
5907 CONVERT_CHECKED(String, y, args[1]);
5908
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005909 bool not_equal = !x->Equals(y);
5910 // This is slightly convoluted because the value that signifies
5911 // equality is 0 and inequality is 1 so we have to negate the result
5912 // from String::Equals.
5913 ASSERT(not_equal == 0 || not_equal == 1);
5914 STATIC_CHECK(EQUAL == 0);
5915 STATIC_CHECK(NOT_EQUAL == 1);
5916 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005917}
5918
5919
lrn@chromium.org303ada72010-10-27 09:33:13 +00005920static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921 NoHandleAllocation ha;
5922 ASSERT(args.length() == 3);
5923
5924 CONVERT_DOUBLE_CHECKED(x, args[0]);
5925 CONVERT_DOUBLE_CHECKED(y, args[1]);
5926 if (isnan(x) || isnan(y)) return args[2];
5927 if (x == y) return Smi::FromInt(EQUAL);
5928 if (isless(x, y)) return Smi::FromInt(LESS);
5929 return Smi::FromInt(GREATER);
5930}
5931
5932
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005933// Compare two Smis as if they were converted to strings and then
5934// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005935static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005936 NoHandleAllocation ha;
5937 ASSERT(args.length() == 2);
5938
5939 // Arrays for the individual characters of the two Smis. Smis are
5940 // 31 bit integers and 10 decimal digits are therefore enough.
5941 static int x_elms[10];
5942 static int y_elms[10];
5943
5944 // Extract the integer values from the Smis.
5945 CONVERT_CHECKED(Smi, x, args[0]);
5946 CONVERT_CHECKED(Smi, y, args[1]);
5947 int x_value = x->value();
5948 int y_value = y->value();
5949
5950 // If the integers are equal so are the string representations.
5951 if (x_value == y_value) return Smi::FromInt(EQUAL);
5952
5953 // If one of the integers are zero the normal integer order is the
5954 // same as the lexicographic order of the string representations.
5955 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5956
ager@chromium.org32912102009-01-16 10:38:43 +00005957 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005958 // smallest because the char code of '-' is less than the char code
5959 // of any digit. Otherwise, we make both values positive.
5960 if (x_value < 0 || y_value < 0) {
5961 if (y_value >= 0) return Smi::FromInt(LESS);
5962 if (x_value >= 0) return Smi::FromInt(GREATER);
5963 x_value = -x_value;
5964 y_value = -y_value;
5965 }
5966
5967 // Convert the integers to arrays of their decimal digits.
5968 int x_index = 0;
5969 int y_index = 0;
5970 while (x_value > 0) {
5971 x_elms[x_index++] = x_value % 10;
5972 x_value /= 10;
5973 }
5974 while (y_value > 0) {
5975 y_elms[y_index++] = y_value % 10;
5976 y_value /= 10;
5977 }
5978
5979 // Loop through the arrays of decimal digits finding the first place
5980 // where they differ.
5981 while (--x_index >= 0 && --y_index >= 0) {
5982 int diff = x_elms[x_index] - y_elms[y_index];
5983 if (diff != 0) return Smi::FromInt(diff);
5984 }
5985
5986 // If one array is a suffix of the other array, the longest array is
5987 // the representation of the largest of the Smis in the
5988 // lexicographic ordering.
5989 return Smi::FromInt(x_index - y_index);
5990}
5991
5992
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005993static Object* StringInputBufferCompare(String* x, String* y) {
5994 static StringInputBuffer bufx;
5995 static StringInputBuffer bufy;
5996 bufx.Reset(x);
5997 bufy.Reset(y);
5998 while (bufx.has_more() && bufy.has_more()) {
5999 int d = bufx.GetNext() - bufy.GetNext();
6000 if (d < 0) return Smi::FromInt(LESS);
6001 else if (d > 0) return Smi::FromInt(GREATER);
6002 }
6003
6004 // x is (non-trivial) prefix of y:
6005 if (bufy.has_more()) return Smi::FromInt(LESS);
6006 // y is prefix of x:
6007 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6008}
6009
6010
6011static Object* FlatStringCompare(String* x, String* y) {
6012 ASSERT(x->IsFlat());
6013 ASSERT(y->IsFlat());
6014 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6015 int prefix_length = x->length();
6016 if (y->length() < prefix_length) {
6017 prefix_length = y->length();
6018 equal_prefix_result = Smi::FromInt(GREATER);
6019 } else if (y->length() > prefix_length) {
6020 equal_prefix_result = Smi::FromInt(LESS);
6021 }
6022 int r;
6023 if (x->IsAsciiRepresentation()) {
6024 Vector<const char> x_chars = x->ToAsciiVector();
6025 if (y->IsAsciiRepresentation()) {
6026 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006027 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006028 } else {
6029 Vector<const uc16> y_chars = y->ToUC16Vector();
6030 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6031 }
6032 } else {
6033 Vector<const uc16> x_chars = x->ToUC16Vector();
6034 if (y->IsAsciiRepresentation()) {
6035 Vector<const char> y_chars = y->ToAsciiVector();
6036 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6037 } else {
6038 Vector<const uc16> y_chars = y->ToUC16Vector();
6039 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6040 }
6041 }
6042 Object* result;
6043 if (r == 0) {
6044 result = equal_prefix_result;
6045 } else {
6046 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6047 }
6048 ASSERT(result == StringInputBufferCompare(x, y));
6049 return result;
6050}
6051
6052
lrn@chromium.org303ada72010-10-27 09:33:13 +00006053static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006054 NoHandleAllocation ha;
6055 ASSERT(args.length() == 2);
6056
6057 CONVERT_CHECKED(String, x, args[0]);
6058 CONVERT_CHECKED(String, y, args[1]);
6059
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006060 Counters::string_compare_runtime.Increment();
6061
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006062 // A few fast case tests before we flatten.
6063 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006064 if (y->length() == 0) {
6065 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006066 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006067 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006068 return Smi::FromInt(LESS);
6069 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006070
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006071 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006072 if (d < 0) return Smi::FromInt(LESS);
6073 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006074
lrn@chromium.org303ada72010-10-27 09:33:13 +00006075 Object* obj;
6076 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
6077 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6078 }
6079 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
6080 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6081 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006082
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006083 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
6084 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006085}
6086
6087
lrn@chromium.org303ada72010-10-27 09:33:13 +00006088static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006089 NoHandleAllocation ha;
6090 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006091 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006092
6093 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006094 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006095}
6096
6097
lrn@chromium.org303ada72010-10-27 09:33:13 +00006098static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006099 NoHandleAllocation ha;
6100 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006101 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006102
6103 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006104 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006105}
6106
6107
lrn@chromium.org303ada72010-10-27 09:33:13 +00006108static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006109 NoHandleAllocation ha;
6110 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006111 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006112
6113 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006114 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006115}
6116
6117
lrn@chromium.org303ada72010-10-27 09:33:13 +00006118static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006119 NoHandleAllocation ha;
6120 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006121 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006122
6123 CONVERT_DOUBLE_CHECKED(x, args[0]);
6124 CONVERT_DOUBLE_CHECKED(y, args[1]);
6125 double result;
6126 if (isinf(x) && isinf(y)) {
6127 // Make sure that the result in case of two infinite arguments
6128 // is a multiple of Pi / 4. The sign of the result is determined
6129 // by the first argument (x) and the sign of the second argument
6130 // determines the multiplier: one or three.
6131 static double kPiDividedBy4 = 0.78539816339744830962;
6132 int multiplier = (x < 0) ? -1 : 1;
6133 if (y < 0) multiplier *= 3;
6134 result = multiplier * kPiDividedBy4;
6135 } else {
6136 result = atan2(x, y);
6137 }
6138 return Heap::AllocateHeapNumber(result);
6139}
6140
6141
lrn@chromium.org303ada72010-10-27 09:33:13 +00006142static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006143 NoHandleAllocation ha;
6144 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006145 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006146
6147 CONVERT_DOUBLE_CHECKED(x, args[0]);
6148 return Heap::NumberFromDouble(ceiling(x));
6149}
6150
6151
lrn@chromium.org303ada72010-10-27 09:33:13 +00006152static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006153 NoHandleAllocation ha;
6154 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006155 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006156
6157 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006158 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006159}
6160
6161
lrn@chromium.org303ada72010-10-27 09:33:13 +00006162static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006163 NoHandleAllocation ha;
6164 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006165 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006166
6167 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006168 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006169}
6170
6171
lrn@chromium.org303ada72010-10-27 09:33:13 +00006172static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006173 NoHandleAllocation ha;
6174 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006175 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006176
6177 CONVERT_DOUBLE_CHECKED(x, args[0]);
6178 return Heap::NumberFromDouble(floor(x));
6179}
6180
6181
lrn@chromium.org303ada72010-10-27 09:33:13 +00006182static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006183 NoHandleAllocation ha;
6184 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006185 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006186
6187 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006188 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006189}
6190
6191
lrn@chromium.org303ada72010-10-27 09:33:13 +00006192static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006193 NoHandleAllocation ha;
6194 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006195 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006196
6197 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006198
6199 // If the second argument is a smi, it is much faster to call the
6200 // custom powi() function than the generic pow().
6201 if (args[1]->IsSmi()) {
6202 int y = Smi::cast(args[1])->value();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006203 return Heap::NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006204 }
6205
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006206 CONVERT_DOUBLE_CHECKED(y, args[1]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006207 return Heap::AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006208}
6209
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006210// Fast version of Math.pow if we know that y is not an integer and
6211// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006212static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006213 NoHandleAllocation ha;
6214 ASSERT(args.length() == 2);
6215 CONVERT_DOUBLE_CHECKED(x, args[0]);
6216 CONVERT_DOUBLE_CHECKED(y, args[1]);
6217 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006218 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006219 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006220 return Heap::nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006221 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006222 return Heap::AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006223 }
6224}
6225
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006226
lrn@chromium.org303ada72010-10-27 09:33:13 +00006227static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006228 NoHandleAllocation ha;
6229 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006230 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006231
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006232 if (!args[0]->IsHeapNumber()) {
6233 // Must be smi. Return the argument unchanged for all the other types
6234 // to make fuzz-natives test happy.
6235 return args[0];
6236 }
6237
6238 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6239
6240 double value = number->value();
6241 int exponent = number->get_exponent();
6242 int sign = number->get_sign();
6243
6244 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6245 // should be rounded to 2^30, which is not smi.
6246 if (!sign && exponent <= kSmiValueSize - 3) {
6247 return Smi::FromInt(static_cast<int>(value + 0.5));
6248 }
6249
6250 // If the magnitude is big enough, there's no place for fraction part. If we
6251 // try to add 0.5 to this number, 1.0 will be added instead.
6252 if (exponent >= 52) {
6253 return number;
6254 }
6255
6256 if (sign && value >= -0.5) return Heap::minus_zero_value();
6257
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006258 // Do not call NumberFromDouble() to avoid extra checks.
6259 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006260}
6261
6262
lrn@chromium.org303ada72010-10-27 09:33:13 +00006263static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006264 NoHandleAllocation ha;
6265 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006266 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006267
6268 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006269 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006270}
6271
6272
lrn@chromium.org303ada72010-10-27 09:33:13 +00006273static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006274 NoHandleAllocation ha;
6275 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006276 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006277
6278 CONVERT_DOUBLE_CHECKED(x, args[0]);
6279 return Heap::AllocateHeapNumber(sqrt(x));
6280}
6281
6282
lrn@chromium.org303ada72010-10-27 09:33:13 +00006283static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006284 NoHandleAllocation ha;
6285 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006286 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006287
6288 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006289 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006290}
6291
6292
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006293static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006294 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6295 181, 212, 243, 273, 304, 334};
6296 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6297 182, 213, 244, 274, 305, 335};
6298
6299 year += month / 12;
6300 month %= 12;
6301 if (month < 0) {
6302 year--;
6303 month += 12;
6304 }
6305
6306 ASSERT(month >= 0);
6307 ASSERT(month < 12);
6308
6309 // year_delta is an arbitrary number such that:
6310 // a) year_delta = -1 (mod 400)
6311 // b) year + year_delta > 0 for years in the range defined by
6312 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6313 // Jan 1 1970. This is required so that we don't run into integer
6314 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006315 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006316 // operations.
6317 static const int year_delta = 399999;
6318 static const int base_day = 365 * (1970 + year_delta) +
6319 (1970 + year_delta) / 4 -
6320 (1970 + year_delta) / 100 +
6321 (1970 + year_delta) / 400;
6322
6323 int year1 = year + year_delta;
6324 int day_from_year = 365 * year1 +
6325 year1 / 4 -
6326 year1 / 100 +
6327 year1 / 400 -
6328 base_day;
6329
6330 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006331 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006332 }
6333
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006334 return day_from_year + day_from_month_leap[month] + day - 1;
6335}
6336
6337
lrn@chromium.org303ada72010-10-27 09:33:13 +00006338static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006339 NoHandleAllocation ha;
6340 ASSERT(args.length() == 3);
6341
6342 CONVERT_SMI_CHECKED(year, args[0]);
6343 CONVERT_SMI_CHECKED(month, args[1]);
6344 CONVERT_SMI_CHECKED(date, args[2]);
6345
6346 return Smi::FromInt(MakeDay(year, month, date));
6347}
6348
6349
6350static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6351static const int kDaysIn4Years = 4 * 365 + 1;
6352static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6353static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6354static const int kDays1970to2000 = 30 * 365 + 7;
6355static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6356 kDays1970to2000;
6357static const int kYearsOffset = 400000;
6358
6359static const char kDayInYear[] = {
6360 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6361 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6362 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6363 22, 23, 24, 25, 26, 27, 28,
6364 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6365 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6366 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6367 22, 23, 24, 25, 26, 27, 28, 29, 30,
6368 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6369 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6370 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6371 22, 23, 24, 25, 26, 27, 28, 29, 30,
6372 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6373 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6374 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6375 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6376 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6377 22, 23, 24, 25, 26, 27, 28, 29, 30,
6378 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6379 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6380 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6381 22, 23, 24, 25, 26, 27, 28, 29, 30,
6382 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6383 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6384
6385 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6386 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6387 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6388 22, 23, 24, 25, 26, 27, 28,
6389 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6390 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6391 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6392 22, 23, 24, 25, 26, 27, 28, 29, 30,
6393 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6394 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6395 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6396 22, 23, 24, 25, 26, 27, 28, 29, 30,
6397 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6398 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6399 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6400 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6401 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6402 22, 23, 24, 25, 26, 27, 28, 29, 30,
6403 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6404 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6405 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6406 22, 23, 24, 25, 26, 27, 28, 29, 30,
6407 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6408 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6409
6410 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6411 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6412 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6413 22, 23, 24, 25, 26, 27, 28, 29,
6414 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6415 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6416 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6417 22, 23, 24, 25, 26, 27, 28, 29, 30,
6418 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6419 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6420 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6421 22, 23, 24, 25, 26, 27, 28, 29, 30,
6422 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6423 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6424 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6425 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6426 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6427 22, 23, 24, 25, 26, 27, 28, 29, 30,
6428 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6429 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6430 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6431 22, 23, 24, 25, 26, 27, 28, 29, 30,
6432 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6433 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6434
6435 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6436 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6437 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6438 22, 23, 24, 25, 26, 27, 28,
6439 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6440 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6441 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6442 22, 23, 24, 25, 26, 27, 28, 29, 30,
6443 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6444 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6445 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6446 22, 23, 24, 25, 26, 27, 28, 29, 30,
6447 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6448 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6449 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6450 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6451 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6452 22, 23, 24, 25, 26, 27, 28, 29, 30,
6453 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6454 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6455 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6456 22, 23, 24, 25, 26, 27, 28, 29, 30,
6457 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6458 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6459
6460static const char kMonthInYear[] = {
6461 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,
6462 0, 0, 0, 0, 0, 0,
6463 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,
6464 1, 1, 1,
6465 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,
6466 2, 2, 2, 2, 2, 2,
6467 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,
6468 3, 3, 3, 3, 3,
6469 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,
6470 4, 4, 4, 4, 4, 4,
6471 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,
6472 5, 5, 5, 5, 5,
6473 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,
6474 6, 6, 6, 6, 6, 6,
6475 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,
6476 7, 7, 7, 7, 7, 7,
6477 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,
6478 8, 8, 8, 8, 8,
6479 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,
6480 9, 9, 9, 9, 9, 9,
6481 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6482 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6483 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6484 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6485
6486 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,
6487 0, 0, 0, 0, 0, 0,
6488 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,
6489 1, 1, 1,
6490 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,
6491 2, 2, 2, 2, 2, 2,
6492 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,
6493 3, 3, 3, 3, 3,
6494 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,
6495 4, 4, 4, 4, 4, 4,
6496 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,
6497 5, 5, 5, 5, 5,
6498 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,
6499 6, 6, 6, 6, 6, 6,
6500 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,
6501 7, 7, 7, 7, 7, 7,
6502 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,
6503 8, 8, 8, 8, 8,
6504 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,
6505 9, 9, 9, 9, 9, 9,
6506 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6507 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6508 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6509 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6510
6511 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,
6512 0, 0, 0, 0, 0, 0,
6513 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,
6514 1, 1, 1, 1,
6515 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,
6516 2, 2, 2, 2, 2, 2,
6517 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,
6518 3, 3, 3, 3, 3,
6519 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,
6520 4, 4, 4, 4, 4, 4,
6521 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,
6522 5, 5, 5, 5, 5,
6523 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,
6524 6, 6, 6, 6, 6, 6,
6525 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,
6526 7, 7, 7, 7, 7, 7,
6527 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,
6528 8, 8, 8, 8, 8,
6529 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,
6530 9, 9, 9, 9, 9, 9,
6531 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6532 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6533 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6534 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6535
6536 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,
6537 0, 0, 0, 0, 0, 0,
6538 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,
6539 1, 1, 1,
6540 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,
6541 2, 2, 2, 2, 2, 2,
6542 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,
6543 3, 3, 3, 3, 3,
6544 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,
6545 4, 4, 4, 4, 4, 4,
6546 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,
6547 5, 5, 5, 5, 5,
6548 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,
6549 6, 6, 6, 6, 6, 6,
6550 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,
6551 7, 7, 7, 7, 7, 7,
6552 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,
6553 8, 8, 8, 8, 8,
6554 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,
6555 9, 9, 9, 9, 9, 9,
6556 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6557 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6558 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6559 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6560
6561
6562// This function works for dates from 1970 to 2099.
6563static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006564 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006565#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006566 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006567#endif
6568
6569 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6570 date %= kDaysIn4Years;
6571
6572 month = kMonthInYear[date];
6573 day = kDayInYear[date];
6574
6575 ASSERT(MakeDay(year, month, day) == save_date);
6576}
6577
6578
6579static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006580 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006581#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006582 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006583#endif
6584
6585 date += kDaysOffset;
6586 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6587 date %= kDaysIn400Years;
6588
6589 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6590
6591 date--;
6592 int yd1 = date / kDaysIn100Years;
6593 date %= kDaysIn100Years;
6594 year += 100 * yd1;
6595
6596 date++;
6597 int yd2 = date / kDaysIn4Years;
6598 date %= kDaysIn4Years;
6599 year += 4 * yd2;
6600
6601 date--;
6602 int yd3 = date / 365;
6603 date %= 365;
6604 year += yd3;
6605
6606 bool is_leap = (!yd1 || yd2) && !yd3;
6607
6608 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006609 ASSERT(is_leap || (date >= 0));
6610 ASSERT((date < 365) || (is_leap && (date < 366)));
6611 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6612 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6613 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006614
6615 if (is_leap) {
6616 day = kDayInYear[2*365 + 1 + date];
6617 month = kMonthInYear[2*365 + 1 + date];
6618 } else {
6619 day = kDayInYear[date];
6620 month = kMonthInYear[date];
6621 }
6622
6623 ASSERT(MakeDay(year, month, day) == save_date);
6624}
6625
6626
6627static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006628 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006629 if (date >= 0 && date < 32 * kDaysIn4Years) {
6630 DateYMDFromTimeAfter1970(date, year, month, day);
6631 } else {
6632 DateYMDFromTimeSlow(date, year, month, day);
6633 }
6634}
6635
6636
lrn@chromium.org303ada72010-10-27 09:33:13 +00006637static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006638 NoHandleAllocation ha;
6639 ASSERT(args.length() == 2);
6640
6641 CONVERT_DOUBLE_CHECKED(t, args[0]);
6642 CONVERT_CHECKED(JSArray, res_array, args[1]);
6643
6644 int year, month, day;
6645 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6646
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006647 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6648 FixedArray* elms = FixedArray::cast(res_array->elements());
6649 RUNTIME_ASSERT(elms->length() == 3);
6650
6651 elms->set(0, Smi::FromInt(year));
6652 elms->set(1, Smi::FromInt(month));
6653 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006654
6655 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006656}
6657
6658
lrn@chromium.org303ada72010-10-27 09:33:13 +00006659static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006660 NoHandleAllocation ha;
6661 ASSERT(args.length() == 3);
6662
6663 JSFunction* callee = JSFunction::cast(args[0]);
6664 Object** parameters = reinterpret_cast<Object**>(args[1]);
6665 const int length = Smi::cast(args[2])->value();
6666
lrn@chromium.org303ada72010-10-27 09:33:13 +00006667 Object* result;
6668 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6669 if (!maybe_result->ToObject(&result)) return maybe_result;
6670 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006671 // Allocate the elements if needed.
6672 if (length > 0) {
6673 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006674 Object* obj;
6675 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6676 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6677 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006678
6679 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006680 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6681 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006682 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006683
6684 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006685 for (int i = 0; i < length; i++) {
6686 array->set(i, *--parameters, mode);
6687 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006688 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006689 }
6690 return result;
6691}
6692
6693
lrn@chromium.org303ada72010-10-27 09:33:13 +00006694static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006695 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006696 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006697 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006698 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006699 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006700
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006701 // Allocate global closures in old space and allocate local closures
6702 // in new space. Additionally pretenure closures that are assigned
6703 // directly to properties.
6704 pretenure = pretenure || (context->global_context() == *context);
6705 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006706 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006707 Factory::NewFunctionFromSharedFunctionInfo(shared,
6708 context,
6709 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006710 return *result;
6711}
6712
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006713
lrn@chromium.org303ada72010-10-27 09:33:13 +00006714static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006715 HandleScope scope;
6716 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006717 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006718 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006719
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006720 // Second argument is either null or an array of bound arguments.
6721 FixedArray* bound_args = NULL;
6722 int bound_argc = 0;
6723 if (!args[1]->IsNull()) {
6724 CONVERT_ARG_CHECKED(JSArray, params, 1);
6725 RUNTIME_ASSERT(params->HasFastElements());
6726 bound_args = FixedArray::cast(params->elements());
6727 bound_argc = Smi::cast(params->length())->value();
6728 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006729
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006730 // Find frame containing arguments passed to the caller.
6731 JavaScriptFrameIterator it;
6732 JavaScriptFrame* frame = it.frame();
6733 ASSERT(!frame->is_optimized());
6734 it.AdvanceToArgumentsFrame();
6735 frame = it.frame();
6736 int argc = frame->GetProvidedParametersCount();
6737
6738 // Prepend bound arguments to caller's arguments.
6739 int total_argc = bound_argc + argc;
6740 SmartPointer<Object**> param_data(NewArray<Object**>(total_argc));
6741 for (int i = 0; i < bound_argc; i++) {
6742 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006743 param_data[i] = val.location();
6744 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006745 for (int i = 0; i < argc; i++) {
6746 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
6747 param_data[bound_argc + i] = val.location();
6748 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006749
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006750 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006751 Handle<Object> result =
6752 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006753 if (exception) {
6754 return Failure::Exception();
6755 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006756
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006757 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006758 return *result;
6759}
6760
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006761
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006762static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006763 Handle<Object> prototype = Factory::null_value();
6764 if (function->has_instance_prototype()) {
6765 prototype = Handle<Object>(function->instance_prototype());
6766 }
6767 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006768 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006769 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006770 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006771 function->shared()->set_construct_stub(
6772 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006773 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006774 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006775}
6776
6777
lrn@chromium.org303ada72010-10-27 09:33:13 +00006778static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006779 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006780 ASSERT(args.length() == 1);
6781
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006782 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006783
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006784 // If the constructor isn't a proper function we throw a type error.
6785 if (!constructor->IsJSFunction()) {
6786 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6787 Handle<Object> type_error =
6788 Factory::NewTypeError("not_constructor", arguments);
6789 return Top::Throw(*type_error);
6790 }
6791
6792 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006793
6794 // If function should not have prototype, construction is not allowed. In this
6795 // case generated code bailouts here, since function has no initial_map.
6796 if (!function->should_have_prototype()) {
6797 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6798 Handle<Object> type_error =
6799 Factory::NewTypeError("not_constructor", arguments);
6800 return Top::Throw(*type_error);
6801 }
6802
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006803#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006804 // Handle stepping into constructors if step into is active.
6805 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006806 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006807 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006808#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006809
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006810 if (function->has_initial_map()) {
6811 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006812 // The 'Function' function ignores the receiver object when
6813 // called using 'new' and creates a new JSFunction object that
6814 // is returned. The receiver object is only used for error
6815 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006816 // JSFunction. Factory::NewJSObject() should not be used to
6817 // allocate JSFunctions since it does not properly initialize
6818 // the shared part of the function. Since the receiver is
6819 // ignored anyway, we use the global object as the receiver
6820 // instead of a new JSFunction object. This way, errors are
6821 // reported the same way whether or not 'Function' is called
6822 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006823 return Top::context()->global();
6824 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006825 }
6826
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006827 // The function should be compiled for the optimization hints to be
6828 // available. We cannot use EnsureCompiled because that forces a
6829 // compilation through the shared function info which makes it
6830 // impossible for us to optimize.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006831 Handle<SharedFunctionInfo> shared(function->shared());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006832 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006833
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006834 if (!function->has_initial_map() &&
6835 shared->IsInobjectSlackTrackingInProgress()) {
6836 // The tracking is already in progress for another function. We can only
6837 // track one initial_map at a time, so we force the completion before the
6838 // function is called as a constructor for the first time.
6839 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006840 }
6841
6842 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006843 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006844 // Delay setting the stub if inobject slack tracking is in progress.
6845 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6846 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006847 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006848
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006849 Counters::constructed_objects.Increment();
6850 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006851
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006852 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006853}
6854
6855
lrn@chromium.org303ada72010-10-27 09:33:13 +00006856static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006857 HandleScope scope;
6858 ASSERT(args.length() == 1);
6859
6860 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6861 function->shared()->CompleteInobjectSlackTracking();
6862 TrySettingInlineConstructStub(function);
6863
6864 return Heap::undefined_value();
6865}
6866
6867
lrn@chromium.org303ada72010-10-27 09:33:13 +00006868static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006869 HandleScope scope;
6870 ASSERT(args.length() == 1);
6871
6872 Handle<JSFunction> function = args.at<JSFunction>(0);
6873#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006874 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006875 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006876 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006877 PrintF("]\n");
6878 }
6879#endif
6880
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006881 // Compile the target function. Here we compile using CompileLazyInLoop in
6882 // order to get the optimized version. This helps code like delta-blue
6883 // that calls performance-critical routines through constructors. A
6884 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6885 // direct call. Since the in-loop tracking takes place through CallICs
6886 // this means that things called through constructors are never known to
6887 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006888 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006889 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006890 return Failure::Exception();
6891 }
6892
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006893 // All done. Return the compiled code.
6894 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006895 return function->code();
6896}
6897
6898
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006899static MaybeObject* Runtime_LazyRecompile(Arguments args) {
6900 HandleScope scope;
6901 ASSERT(args.length() == 1);
6902 Handle<JSFunction> function = args.at<JSFunction>(0);
6903 // If the function is not optimizable or debugger is active continue using the
6904 // code from the full compiler.
6905 if (!function->shared()->code()->optimizable() ||
6906 Debug::has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006907 if (FLAG_trace_opt) {
6908 PrintF("[failed to optimize ");
6909 function->PrintName();
6910 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
6911 function->shared()->code()->optimizable() ? "T" : "F",
6912 Debug::has_break_points() ? "T" : "F");
6913 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006914 function->ReplaceCode(function->shared()->code());
6915 return function->code();
6916 }
6917 if (CompileOptimized(function, AstNode::kNoNumber)) {
6918 return function->code();
6919 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006920 if (FLAG_trace_opt) {
6921 PrintF("[failed to optimize ");
6922 function->PrintName();
6923 PrintF(": optimized compilation failed]\n");
6924 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006925 function->ReplaceCode(function->shared()->code());
6926 return Failure::Exception();
6927}
6928
6929
6930static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
6931 HandleScope scope;
6932 ASSERT(args.length() == 1);
6933 RUNTIME_ASSERT(args[0]->IsSmi());
6934 Deoptimizer::BailoutType type =
6935 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
6936 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6937 ASSERT(Heap::IsAllocationAllowed());
6938 int frames = deoptimizer->output_count();
6939
6940 JavaScriptFrameIterator it;
6941 JavaScriptFrame* frame = NULL;
6942 for (int i = 0; i < frames; i++) {
6943 if (i != 0) it.Advance();
6944 frame = it.frame();
6945 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
6946 }
6947 delete deoptimizer;
6948
6949 RUNTIME_ASSERT(frame->function()->IsJSFunction());
6950 Handle<JSFunction> function(JSFunction::cast(frame->function()));
6951 Handle<Object> arguments;
6952 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00006953 if (frame->GetExpression(i) == Heap::arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006954 if (arguments.is_null()) {
6955 // FunctionGetArguments can't throw an exception, so cast away the
6956 // doubt with an assert.
6957 arguments = Handle<Object>(
6958 Accessors::FunctionGetArguments(*function,
6959 NULL)->ToObjectUnchecked());
6960 ASSERT(*arguments != Heap::null_value());
6961 ASSERT(*arguments != Heap::undefined_value());
6962 }
6963 frame->SetExpression(i, *arguments);
6964 }
6965 }
6966
6967 CompilationCache::MarkForLazyOptimizing(function);
6968 if (type == Deoptimizer::EAGER) {
6969 RUNTIME_ASSERT(function->IsOptimized());
6970 } else {
6971 RUNTIME_ASSERT(!function->IsOptimized());
6972 }
6973
6974 // Avoid doing too much work when running with --always-opt and keep
6975 // the optimized code around.
6976 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
6977 return Heap::undefined_value();
6978 }
6979
6980 // Count the number of optimized activations of the function.
6981 int activations = 0;
6982 while (!it.done()) {
6983 JavaScriptFrame* frame = it.frame();
6984 if (frame->is_optimized() && frame->function() == *function) {
6985 activations++;
6986 }
6987 it.Advance();
6988 }
6989
6990 // TODO(kasperl): For now, we cannot support removing the optimized
6991 // code when we have recursive invocations of the same function.
6992 if (activations == 0) {
6993 if (FLAG_trace_deopt) {
6994 PrintF("[removing optimized code for: ");
6995 function->PrintName();
6996 PrintF("]\n");
6997 }
6998 function->ReplaceCode(function->shared()->code());
6999 }
7000 return Heap::undefined_value();
7001}
7002
7003
7004static MaybeObject* Runtime_NotifyOSR(Arguments args) {
7005 Deoptimizer* deoptimizer = Deoptimizer::Grab();
7006 delete deoptimizer;
7007 return Heap::undefined_value();
7008}
7009
7010
7011static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
7012 HandleScope scope;
7013 ASSERT(args.length() == 1);
7014 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7015 if (!function->IsOptimized()) return Heap::undefined_value();
7016
7017 Deoptimizer::DeoptimizeFunction(*function);
7018
7019 return Heap::undefined_value();
7020}
7021
7022
7023static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
7024 HandleScope scope;
7025 ASSERT(args.length() == 1);
7026 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7027
7028 // We're not prepared to handle a function with arguments object.
7029 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7030
7031 // We have hit a back edge in an unoptimized frame for a function that was
7032 // selected for on-stack replacement. Find the unoptimized code object.
7033 Handle<Code> unoptimized(function->shared()->code());
7034 // Keep track of whether we've succeeded in optimizing.
7035 bool succeeded = unoptimized->optimizable();
7036 if (succeeded) {
7037 // If we are trying to do OSR when there are already optimized
7038 // activations of the function, it means (a) the function is directly or
7039 // indirectly recursive and (b) an optimized invocation has been
7040 // deoptimized so that we are currently in an unoptimized activation.
7041 // Check for optimized activations of this function.
7042 JavaScriptFrameIterator it;
7043 while (succeeded && !it.done()) {
7044 JavaScriptFrame* frame = it.frame();
7045 succeeded = !frame->is_optimized() || frame->function() != *function;
7046 it.Advance();
7047 }
7048 }
7049
7050 int ast_id = AstNode::kNoNumber;
7051 if (succeeded) {
7052 // The top JS function is this one, the PC is somewhere in the
7053 // unoptimized code.
7054 JavaScriptFrameIterator it;
7055 JavaScriptFrame* frame = it.frame();
7056 ASSERT(frame->function() == *function);
7057 ASSERT(frame->code() == *unoptimized);
7058 ASSERT(unoptimized->contains(frame->pc()));
7059
7060 // Use linear search of the unoptimized code's stack check table to find
7061 // the AST id matching the PC.
7062 Address start = unoptimized->instruction_start();
7063 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007064 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007065 uint32_t table_length = Memory::uint32_at(table_cursor);
7066 table_cursor += kIntSize;
7067 for (unsigned i = 0; i < table_length; ++i) {
7068 // Table entries are (AST id, pc offset) pairs.
7069 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7070 if (pc_offset == target_pc_offset) {
7071 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7072 break;
7073 }
7074 table_cursor += 2 * kIntSize;
7075 }
7076 ASSERT(ast_id != AstNode::kNoNumber);
7077 if (FLAG_trace_osr) {
7078 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7079 function->PrintName();
7080 PrintF("]\n");
7081 }
7082
7083 // Try to compile the optimized code. A true return value from
7084 // CompileOptimized means that compilation succeeded, not necessarily
7085 // that optimization succeeded.
7086 if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
7087 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7088 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007089 if (data->OsrPcOffset()->value() >= 0) {
7090 if (FLAG_trace_osr) {
7091 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007092 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007093 }
7094 ASSERT(data->OsrAstId()->value() == ast_id);
7095 } else {
7096 // We may never generate the desired OSR entry if we emit an
7097 // early deoptimize.
7098 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007099 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007100 } else {
7101 succeeded = false;
7102 }
7103 }
7104
7105 // Revert to the original stack checks in the original unoptimized code.
7106 if (FLAG_trace_osr) {
7107 PrintF("[restoring original stack checks in ");
7108 function->PrintName();
7109 PrintF("]\n");
7110 }
7111 StackCheckStub check_stub;
7112 Handle<Code> check_code = check_stub.GetCode();
7113 Handle<Code> replacement_code(
7114 Builtins::builtin(Builtins::OnStackReplacement));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007115 Deoptimizer::RevertStackCheckCode(*unoptimized,
7116 *check_code,
7117 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007118
7119 // Allow OSR only at nesting level zero again.
7120 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7121
7122 // If the optimization attempt succeeded, return the AST id tagged as a
7123 // smi. This tells the builtin that we need to translate the unoptimized
7124 // frame to an optimized one.
7125 if (succeeded) {
7126 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7127 return Smi::FromInt(ast_id);
7128 } else {
7129 return Smi::FromInt(-1);
7130 }
7131}
7132
7133
lrn@chromium.org303ada72010-10-27 09:33:13 +00007134static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007135 HandleScope scope;
7136 ASSERT(args.length() == 1);
7137 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7138 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7139}
7140
7141
lrn@chromium.org303ada72010-10-27 09:33:13 +00007142static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007143 HandleScope scope;
7144 ASSERT(args.length() == 1);
7145 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7146 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7147}
7148
7149
lrn@chromium.org303ada72010-10-27 09:33:13 +00007150static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007151 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007152 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007153
kasper.lund7276f142008-07-30 08:49:36 +00007154 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007155 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007156 Object* result;
7157 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
7158 if (!maybe_result->ToObject(&result)) return maybe_result;
7159 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007160
7161 Top::set_context(Context::cast(result));
7162
kasper.lund7276f142008-07-30 08:49:36 +00007163 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007164}
7165
lrn@chromium.org303ada72010-10-27 09:33:13 +00007166
7167MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
7168 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007169 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007170 Object* js_object = object;
7171 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007172 MaybeObject* maybe_js_object = js_object->ToObject();
7173 if (!maybe_js_object->ToObject(&js_object)) {
7174 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7175 return maybe_js_object;
7176 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007177 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007178 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007179 Handle<Object> result =
7180 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
7181 return Top::Throw(*result);
7182 }
7183 }
7184
lrn@chromium.org303ada72010-10-27 09:33:13 +00007185 Object* result;
7186 { MaybeObject* maybe_result =
7187 Heap::AllocateWithContext(Top::context(),
7188 JSObject::cast(js_object),
7189 is_catch_context);
7190 if (!maybe_result->ToObject(&result)) return maybe_result;
7191 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007192
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007193 Context* context = Context::cast(result);
7194 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007195
kasper.lund7276f142008-07-30 08:49:36 +00007196 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007197}
7198
7199
lrn@chromium.org303ada72010-10-27 09:33:13 +00007200static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007201 NoHandleAllocation ha;
7202 ASSERT(args.length() == 1);
7203 return PushContextHelper(args[0], false);
7204}
7205
7206
lrn@chromium.org303ada72010-10-27 09:33:13 +00007207static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007208 NoHandleAllocation ha;
7209 ASSERT(args.length() == 1);
7210 return PushContextHelper(args[0], true);
7211}
7212
7213
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007214static MaybeObject* Runtime_DeleteContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007215 HandleScope scope;
7216 ASSERT(args.length() == 2);
7217
7218 CONVERT_ARG_CHECKED(Context, context, 0);
7219 CONVERT_ARG_CHECKED(String, name, 1);
7220
7221 int index;
7222 PropertyAttributes attributes;
7223 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007224 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007225
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007226 // If the slot was not found the result is true.
7227 if (holder.is_null()) {
7228 return Heap::true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007229 }
7230
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007231 // If the slot was found in a context, it should be DONT_DELETE.
7232 if (holder->IsContext()) {
7233 return Heap::false_value();
7234 }
7235
7236 // The slot was found in a JSObject, either a context extension object,
7237 // the global object, or an arguments object. Try to delete it
7238 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7239 // which allows deleting all parameters in functions that mention
7240 // 'arguments', we do this even for the case of slots found on an
7241 // arguments object. The slot was found on an arguments object if the
7242 // index is non-negative.
7243 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7244 if (index >= 0) {
7245 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7246 } else {
7247 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7248 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007249}
7250
7251
ager@chromium.orga1645e22009-09-09 19:27:10 +00007252// A mechanism to return a pair of Object pointers in registers (if possible).
7253// How this is achieved is calling convention-dependent.
7254// All currently supported x86 compiles uses calling conventions that are cdecl
7255// variants where a 64-bit value is returned in two 32-bit registers
7256// (edx:eax on ia32, r1:r0 on ARM).
7257// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7258// In Win64 calling convention, a struct of two pointers is returned in memory,
7259// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007260#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007261struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007262 MaybeObject* x;
7263 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007264};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007265
lrn@chromium.org303ada72010-10-27 09:33:13 +00007266static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007267 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007268 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7269 // In Win64 they are assigned to a hidden first argument.
7270 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007271}
7272#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007273typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007274static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007275 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007276 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007277}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007278#endif
7279
7280
lrn@chromium.org303ada72010-10-27 09:33:13 +00007281static inline MaybeObject* Unhole(MaybeObject* x,
7282 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007283 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7284 USE(attributes);
7285 return x->IsTheHole() ? Heap::undefined_value() : x;
7286}
7287
7288
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007289static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7290 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007291 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007292 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007293 JSFunction* context_extension_function =
7294 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007295 // If the holder isn't a context extension object, we just return it
7296 // as the receiver. This allows arguments objects to be used as
7297 // receivers, but only if they are put in the context scope chain
7298 // explicitly via a with-statement.
7299 Object* constructor = holder->map()->constructor();
7300 if (constructor != context_extension_function) return holder;
7301 // Fall back to using the global object as the receiver if the
7302 // property turns out to be a local variable allocated in a context
7303 // extension object - introduced via eval.
7304 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007305}
7306
7307
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007308static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007309 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00007310 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007312 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00007313 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007314 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007315 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007316 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007317
7318 int index;
7319 PropertyAttributes attributes;
7320 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007321 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007322
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007323 // If the index is non-negative, the slot has been found in a local
7324 // variable or a parameter. Read it from the context object or the
7325 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007326 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007327 // If the "property" we were looking for is a local variable or an
7328 // argument in a context, the receiver is the global object; see
7329 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7330 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007331 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007332 ? Context::cast(*holder)->get(index)
7333 : JSObject::cast(*holder)->GetElement(index);
7334 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007335 }
7336
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007337 // If the holder is found, we read the property from it.
7338 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007339 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007340 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007341 JSObject* receiver;
7342 if (object->IsGlobalObject()) {
7343 receiver = GlobalObject::cast(object)->global_receiver();
7344 } else if (context->is_exception_holder(*holder)) {
7345 receiver = Top::context()->global()->global_receiver();
7346 } else {
7347 receiver = ComputeReceiverForNonGlobal(object);
7348 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007349 // No need to unhole the value here. This is taken care of by the
7350 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007351 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007352 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007353 }
7354
7355 if (throw_error) {
7356 // The property doesn't exist - throw exception.
7357 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007358 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007359 return MakePair(Top::Throw(*reference_error), NULL);
7360 } else {
7361 // The property doesn't exist - return undefined
7362 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7363 }
7364}
7365
7366
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007367static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007368 return LoadContextSlotHelper(args, true);
7369}
7370
7371
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007372static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007373 return LoadContextSlotHelper(args, false);
7374}
7375
7376
lrn@chromium.org303ada72010-10-27 09:33:13 +00007377static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007378 HandleScope scope;
7379 ASSERT(args.length() == 3);
7380
7381 Handle<Object> value(args[0]);
7382 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007383 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384
7385 int index;
7386 PropertyAttributes attributes;
7387 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007388 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007389
7390 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007391 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007392 // Ignore if read_only variable.
7393 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007394 // Context is a fixed array and set cannot fail.
7395 Context::cast(*holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007396 }
7397 } else {
7398 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007399 Handle<Object> result =
7400 SetElement(Handle<JSObject>::cast(holder), index, value);
7401 if (result.is_null()) {
7402 ASSERT(Top::has_pending_exception());
7403 return Failure::Exception();
7404 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007405 }
7406 return *value;
7407 }
7408
7409 // Slow case: The property is not in a FixedArray context.
7410 // It is either in an JSObject extension context or it was not found.
7411 Handle<JSObject> context_ext;
7412
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007413 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007414 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007415 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007416 } else {
7417 // The property was not found. It needs to be stored in the global context.
7418 ASSERT(attributes == ABSENT);
7419 attributes = NONE;
7420 context_ext = Handle<JSObject>(Top::context()->global());
7421 }
7422
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007423 // Set the property, but ignore if read_only variable on the context
7424 // extension object itself.
7425 if ((attributes & READ_ONLY) == 0 ||
7426 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007427 RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, NONE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007428 }
7429 return *value;
7430}
7431
7432
lrn@chromium.org303ada72010-10-27 09:33:13 +00007433static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007434 HandleScope scope;
7435 ASSERT(args.length() == 1);
7436
7437 return Top::Throw(args[0]);
7438}
7439
7440
lrn@chromium.org303ada72010-10-27 09:33:13 +00007441static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007442 HandleScope scope;
7443 ASSERT(args.length() == 1);
7444
7445 return Top::ReThrow(args[0]);
7446}
7447
7448
lrn@chromium.org303ada72010-10-27 09:33:13 +00007449static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007450 ASSERT_EQ(0, args.length());
7451 return Top::PromoteScheduledException();
7452}
7453
7454
lrn@chromium.org303ada72010-10-27 09:33:13 +00007455static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007456 HandleScope scope;
7457 ASSERT(args.length() == 1);
7458
7459 Handle<Object> name(args[0]);
7460 Handle<Object> reference_error =
7461 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7462 return Top::Throw(*reference_error);
7463}
7464
7465
lrn@chromium.org303ada72010-10-27 09:33:13 +00007466static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007467 NoHandleAllocation na;
7468 return Top::StackOverflow();
7469}
7470
7471
lrn@chromium.org303ada72010-10-27 09:33:13 +00007472static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007473 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007474
7475 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007476 if (StackGuard::IsStackOverflow()) {
7477 return Runtime_StackOverflow(args);
7478 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007479
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007480 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007481}
7482
7483
7484// NOTE: These PrintXXX functions are defined for all builds (not just
7485// DEBUG builds) because we may want to be able to trace function
7486// calls in all modes.
7487static void PrintString(String* str) {
7488 // not uncommon to have empty strings
7489 if (str->length() > 0) {
7490 SmartPointer<char> s =
7491 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7492 PrintF("%s", *s);
7493 }
7494}
7495
7496
7497static void PrintObject(Object* obj) {
7498 if (obj->IsSmi()) {
7499 PrintF("%d", Smi::cast(obj)->value());
7500 } else if (obj->IsString() || obj->IsSymbol()) {
7501 PrintString(String::cast(obj));
7502 } else if (obj->IsNumber()) {
7503 PrintF("%g", obj->Number());
7504 } else if (obj->IsFailure()) {
7505 PrintF("<failure>");
7506 } else if (obj->IsUndefined()) {
7507 PrintF("<undefined>");
7508 } else if (obj->IsNull()) {
7509 PrintF("<null>");
7510 } else if (obj->IsTrue()) {
7511 PrintF("<true>");
7512 } else if (obj->IsFalse()) {
7513 PrintF("<false>");
7514 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007515 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007516 }
7517}
7518
7519
7520static int StackSize() {
7521 int n = 0;
7522 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7523 return n;
7524}
7525
7526
7527static void PrintTransition(Object* result) {
7528 // indentation
7529 { const int nmax = 80;
7530 int n = StackSize();
7531 if (n <= nmax)
7532 PrintF("%4d:%*s", n, n, "");
7533 else
7534 PrintF("%4d:%*s", n, nmax, "...");
7535 }
7536
7537 if (result == NULL) {
7538 // constructor calls
7539 JavaScriptFrameIterator it;
7540 JavaScriptFrame* frame = it.frame();
7541 if (frame->IsConstructor()) PrintF("new ");
7542 // function name
7543 Object* fun = frame->function();
7544 if (fun->IsJSFunction()) {
7545 PrintObject(JSFunction::cast(fun)->shared()->name());
7546 } else {
7547 PrintObject(fun);
7548 }
7549 // function arguments
7550 // (we are intentionally only printing the actually
7551 // supplied parameters, not all parameters required)
7552 PrintF("(this=");
7553 PrintObject(frame->receiver());
7554 const int length = frame->GetProvidedParametersCount();
7555 for (int i = 0; i < length; i++) {
7556 PrintF(", ");
7557 PrintObject(frame->GetParameter(i));
7558 }
7559 PrintF(") {\n");
7560
7561 } else {
7562 // function result
7563 PrintF("} -> ");
7564 PrintObject(result);
7565 PrintF("\n");
7566 }
7567}
7568
7569
lrn@chromium.org303ada72010-10-27 09:33:13 +00007570static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007571 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007572 NoHandleAllocation ha;
7573 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007574 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007575}
7576
7577
lrn@chromium.org303ada72010-10-27 09:33:13 +00007578static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007579 NoHandleAllocation ha;
7580 PrintTransition(args[0]);
7581 return args[0]; // return TOS
7582}
7583
7584
lrn@chromium.org303ada72010-10-27 09:33:13 +00007585static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007586 NoHandleAllocation ha;
7587 ASSERT(args.length() == 1);
7588
7589#ifdef DEBUG
7590 if (args[0]->IsString()) {
7591 // If we have a string, assume it's a code "marker"
7592 // and print some interesting cpu debugging info.
7593 JavaScriptFrameIterator it;
7594 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007595 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7596 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007597 } else {
7598 PrintF("DebugPrint: ");
7599 }
7600 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007601 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007602 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007603 HeapObject::cast(args[0])->map()->Print();
7604 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007605#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007606 // ShortPrint is available in release mode. Print is not.
7607 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007608#endif
7609 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007610 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007611
7612 return args[0]; // return TOS
7613}
7614
7615
lrn@chromium.org303ada72010-10-27 09:33:13 +00007616static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007617 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007618 NoHandleAllocation ha;
7619 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007620 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007621}
7622
7623
lrn@chromium.org303ada72010-10-27 09:33:13 +00007624static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007625 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007626 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007627
7628 // According to ECMA-262, section 15.9.1, page 117, the precision of
7629 // the number in a Date object representing a particular instant in
7630 // time is milliseconds. Therefore, we floor the result of getting
7631 // the OS time.
7632 double millis = floor(OS::TimeCurrentMillis());
7633 return Heap::NumberFromDouble(millis);
7634}
7635
7636
lrn@chromium.org303ada72010-10-27 09:33:13 +00007637static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007638 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007639 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007640
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007641 CONVERT_ARG_CHECKED(String, str, 0);
7642 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007643
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007644 CONVERT_ARG_CHECKED(JSArray, output, 1);
7645 RUNTIME_ASSERT(output->HasFastElements());
7646
7647 AssertNoAllocation no_allocation;
7648
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007649 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007650 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7651 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007652 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007653 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007654 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007655 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007656 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7657 }
7658
7659 if (result) {
7660 return *output;
7661 } else {
7662 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007663 }
7664}
7665
7666
lrn@chromium.org303ada72010-10-27 09:33:13 +00007667static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007668 NoHandleAllocation ha;
7669 ASSERT(args.length() == 1);
7670
7671 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007672 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007673 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7674}
7675
7676
lrn@chromium.org303ada72010-10-27 09:33:13 +00007677static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007678 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007679 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007680
7681 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7682}
7683
7684
lrn@chromium.org303ada72010-10-27 09:33:13 +00007685static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007686 NoHandleAllocation ha;
7687 ASSERT(args.length() == 1);
7688
7689 CONVERT_DOUBLE_CHECKED(x, args[0]);
7690 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7691}
7692
7693
lrn@chromium.org303ada72010-10-27 09:33:13 +00007694static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007695 ASSERT(args.length() == 1);
7696 Object* global = args[0];
7697 if (!global->IsJSGlobalObject()) return Heap::null_value();
7698 return JSGlobalObject::cast(global)->global_receiver();
7699}
7700
7701
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007702static MaybeObject* Runtime_ParseJson(Arguments args) {
7703 HandleScope scope;
7704 ASSERT_EQ(1, args.length());
7705 CONVERT_ARG_CHECKED(String, source, 0);
7706
7707 Handle<Object> result = JsonParser::Parse(source);
7708 if (result.is_null()) {
7709 // Syntax error or stack overflow in scanner.
7710 ASSERT(Top::has_pending_exception());
7711 return Failure::Exception();
7712 }
7713 return *result;
7714}
7715
7716
lrn@chromium.org303ada72010-10-27 09:33:13 +00007717static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007718 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007719 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007720 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007721
ager@chromium.org381abbb2009-02-25 13:23:22 +00007722 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007723 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007724 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7725 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007726 true,
7727 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007728 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007729 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007730 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007731 return *fun;
7732}
7733
7734
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007735static ObjectPair CompileGlobalEval(Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007736 Handle<Object> receiver,
7737 StrictModeFlag mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007738 // Deal with a normal eval call with a string argument. Compile it
7739 // and return the compiled function bound in the local context.
7740 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7741 source,
7742 Handle<Context>(Top::context()),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007743 Top::context()->IsGlobalContext(),
7744 mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007745 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7746 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7747 shared,
7748 Handle<Context>(Top::context()),
7749 NOT_TENURED);
7750 return MakePair(*compiled, *receiver);
7751}
7752
7753
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007754static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007755 ASSERT(args.length() == 4);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007756 if (!args[0]->IsJSFunction()) {
7757 return MakePair(Top::ThrowIllegalOperation(), NULL);
7758 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007759
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007760 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007761 Handle<JSFunction> callee = args.at<JSFunction>(0);
7762 Handle<Object> receiver; // Will be overwritten.
7763
7764 // Compute the calling context.
7765 Handle<Context> context = Handle<Context>(Top::context());
7766#ifdef DEBUG
7767 // Make sure Top::context() agrees with the old code that traversed
7768 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007769 StackFrameLocator locator;
7770 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007771 ASSERT(Context::cast(frame->context()) == *context);
7772#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007773
7774 // Find where the 'eval' symbol is bound. It is unaliased only if
7775 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007776 int index = -1;
7777 PropertyAttributes attributes = ABSENT;
7778 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007779 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7780 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007781 // Stop search when eval is found or when the global context is
7782 // reached.
7783 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007784 if (context->is_function_context()) {
7785 context = Handle<Context>(Context::cast(context->closure()->context()));
7786 } else {
7787 context = Handle<Context>(context->previous());
7788 }
7789 }
7790
iposva@chromium.org245aa852009-02-10 00:49:54 +00007791 // If eval could not be resolved, it has been deleted and we need to
7792 // throw a reference error.
7793 if (attributes == ABSENT) {
7794 Handle<Object> name = Factory::eval_symbol();
7795 Handle<Object> reference_error =
7796 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007797 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007798 }
7799
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007800 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007801 // 'eval' is not bound in the global context. Just call the function
7802 // with the given arguments. This is not necessarily the global eval.
7803 if (receiver->IsContext()) {
7804 context = Handle<Context>::cast(receiver);
7805 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007806 } else if (receiver->IsJSContextExtensionObject()) {
7807 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007808 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007809 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007810 }
7811
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007812 // 'eval' is bound in the global context, but it may have been overwritten.
7813 // Compare it to the builtin 'GlobalEval' function to make sure.
7814 if (*callee != Top::global_context()->global_eval_fun() ||
7815 !args[1]->IsString()) {
7816 return MakePair(*callee, Top::context()->global()->global_receiver());
7817 }
7818
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007819 ASSERT(args[3]->IsSmi());
7820 return CompileGlobalEval(args.at<String>(1),
7821 args.at<Object>(2),
7822 static_cast<StrictModeFlag>(
7823 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007824}
7825
7826
7827static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007828 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007829 if (!args[0]->IsJSFunction()) {
7830 return MakePair(Top::ThrowIllegalOperation(), NULL);
7831 }
7832
7833 HandleScope scope;
7834 Handle<JSFunction> callee = args.at<JSFunction>(0);
7835
7836 // 'eval' is bound in the global context, but it may have been overwritten.
7837 // Compare it to the builtin 'GlobalEval' function to make sure.
7838 if (*callee != Top::global_context()->global_eval_fun() ||
7839 !args[1]->IsString()) {
7840 return MakePair(*callee, Top::context()->global()->global_receiver());
7841 }
7842
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007843 ASSERT(args[3]->IsSmi());
7844 return CompileGlobalEval(args.at<String>(1),
7845 args.at<Object>(2),
7846 static_cast<StrictModeFlag>(
7847 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007848}
7849
7850
lrn@chromium.org303ada72010-10-27 09:33:13 +00007851static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007852 // This utility adjusts the property attributes for newly created Function
7853 // object ("new Function(...)") by changing the map.
7854 // All it does is changing the prototype property to enumerable
7855 // as specified in ECMA262, 15.3.5.2.
7856 HandleScope scope;
7857 ASSERT(args.length() == 1);
7858 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7859 ASSERT(func->map()->instance_type() ==
7860 Top::function_instance_map()->instance_type());
7861 ASSERT(func->map()->instance_size() ==
7862 Top::function_instance_map()->instance_size());
7863 func->set_map(*Top::function_instance_map());
7864 return *func;
7865}
7866
7867
lrn@chromium.org303ada72010-10-27 09:33:13 +00007868static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007869 // Allocate a block of memory in NewSpace (filled with a filler).
7870 // Use as fallback for allocation in generated code when NewSpace
7871 // is full.
7872 ASSERT(args.length() == 1);
7873 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7874 int size = size_smi->value();
7875 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7876 RUNTIME_ASSERT(size > 0);
7877 static const int kMinFreeNewSpaceAfterGC =
7878 Heap::InitialSemiSpaceSize() * 3/4;
7879 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007880 Object* allocation;
7881 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7882 if (maybe_allocation->ToObject(&allocation)) {
7883 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7884 }
7885 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007886 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007887}
7888
7889
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007890// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007891// array. Returns true if the element was pushed on the stack and
7892// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007893static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007894 ASSERT(args.length() == 2);
7895 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007896 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007897 RUNTIME_ASSERT(array->HasFastElements());
7898 int length = Smi::cast(array->length())->value();
7899 FixedArray* elements = FixedArray::cast(array->elements());
7900 for (int i = 0; i < length; i++) {
7901 if (elements->get(i) == element) return Heap::false_value();
7902 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007903 Object* obj;
7904 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
7905 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7906 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007907 return Heap::true_value();
7908}
7909
7910
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007911/**
7912 * A simple visitor visits every element of Array's.
7913 * The backend storage can be a fixed array for fast elements case,
7914 * or a dictionary for sparse array. Since Dictionary is a subtype
7915 * of FixedArray, the class can be used by both fast and slow cases.
7916 * The second parameter of the constructor, fast_elements, specifies
7917 * whether the storage is a FixedArray or Dictionary.
7918 *
7919 * An index limit is used to deal with the situation that a result array
7920 * length overflows 32-bit non-negative integer.
7921 */
7922class ArrayConcatVisitor {
7923 public:
7924 ArrayConcatVisitor(Handle<FixedArray> storage,
7925 uint32_t index_limit,
7926 bool fast_elements) :
7927 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007928 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007929
7930 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007931 if (i >= index_limit_ - index_offset_) return;
7932 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007933
7934 if (fast_elements_) {
7935 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7936 storage_->set(index, *elm);
7937
7938 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007939 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7940 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007941 Factory::DictionaryAtNumberPut(dict, index, elm);
7942 if (!result.is_identical_to(dict))
7943 storage_ = result;
7944 }
7945 }
7946
7947 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007948 if (index_limit_ - index_offset_ < delta) {
7949 index_offset_ = index_limit_;
7950 } else {
7951 index_offset_ += delta;
7952 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007953 }
7954
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007955 Handle<FixedArray> storage() { return storage_; }
7956
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007957 private:
7958 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007959 // Limit on the accepted indices. Elements with indices larger than the
7960 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007961 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007962 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007963 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007964 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007965};
7966
7967
ager@chromium.org3811b432009-10-28 14:53:37 +00007968template<class ExternalArrayClass, class ElementType>
7969static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7970 bool elements_are_ints,
7971 bool elements_are_guaranteed_smis,
7972 uint32_t range,
7973 ArrayConcatVisitor* visitor) {
7974 Handle<ExternalArrayClass> array(
7975 ExternalArrayClass::cast(receiver->elements()));
7976 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7977
7978 if (visitor != NULL) {
7979 if (elements_are_ints) {
7980 if (elements_are_guaranteed_smis) {
7981 for (uint32_t j = 0; j < len; j++) {
7982 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7983 visitor->visit(j, e);
7984 }
7985 } else {
7986 for (uint32_t j = 0; j < len; j++) {
7987 int64_t val = static_cast<int64_t>(array->get(j));
7988 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7989 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7990 visitor->visit(j, e);
7991 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007992 Handle<Object> e =
7993 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00007994 visitor->visit(j, e);
7995 }
7996 }
7997 }
7998 } else {
7999 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008000 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00008001 visitor->visit(j, e);
8002 }
8003 }
8004 }
8005
8006 return len;
8007}
8008
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008009/**
8010 * A helper function that visits elements of a JSObject. Only elements
8011 * whose index between 0 and range (exclusive) are visited.
8012 *
8013 * If the third parameter, visitor, is not NULL, the visitor is called
8014 * with parameters, 'visitor_index_offset + element index' and the element.
8015 *
8016 * It returns the number of visisted elements.
8017 */
8018static uint32_t IterateElements(Handle<JSObject> receiver,
8019 uint32_t range,
8020 ArrayConcatVisitor* visitor) {
8021 uint32_t num_of_elements = 0;
8022
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008023 switch (receiver->GetElementsKind()) {
8024 case JSObject::FAST_ELEMENTS: {
8025 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8026 uint32_t len = elements->length();
8027 if (range < len) {
8028 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008029 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008030
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008031 for (uint32_t j = 0; j < len; j++) {
8032 Handle<Object> e(elements->get(j));
8033 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008034 num_of_elements++;
8035 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008036 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008037 }
8038 }
8039 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008040 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008041 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008042 case JSObject::PIXEL_ELEMENTS: {
8043 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
8044 uint32_t len = pixels->length();
8045 if (range < len) {
8046 len = range;
8047 }
8048
8049 for (uint32_t j = 0; j < len; j++) {
8050 num_of_elements++;
8051 if (visitor != NULL) {
8052 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8053 visitor->visit(j, e);
8054 }
8055 }
8056 break;
8057 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008058 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8059 num_of_elements =
8060 IterateExternalArrayElements<ExternalByteArray, int8_t>(
8061 receiver, true, true, range, visitor);
8062 break;
8063 }
8064 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8065 num_of_elements =
8066 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
8067 receiver, true, true, range, visitor);
8068 break;
8069 }
8070 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8071 num_of_elements =
8072 IterateExternalArrayElements<ExternalShortArray, int16_t>(
8073 receiver, true, true, range, visitor);
8074 break;
8075 }
8076 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8077 num_of_elements =
8078 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
8079 receiver, true, true, range, visitor);
8080 break;
8081 }
8082 case JSObject::EXTERNAL_INT_ELEMENTS: {
8083 num_of_elements =
8084 IterateExternalArrayElements<ExternalIntArray, int32_t>(
8085 receiver, true, false, range, visitor);
8086 break;
8087 }
8088 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8089 num_of_elements =
8090 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
8091 receiver, true, false, range, visitor);
8092 break;
8093 }
8094 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8095 num_of_elements =
8096 IterateExternalArrayElements<ExternalFloatArray, float>(
8097 receiver, false, false, range, visitor);
8098 break;
8099 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008100 case JSObject::DICTIONARY_ELEMENTS: {
8101 Handle<NumberDictionary> dict(receiver->element_dictionary());
8102 uint32_t capacity = dict->Capacity();
8103 for (uint32_t j = 0; j < capacity; j++) {
8104 Handle<Object> k(dict->KeyAt(j));
8105 if (dict->IsKey(*k)) {
8106 ASSERT(k->IsNumber());
8107 uint32_t index = static_cast<uint32_t>(k->Number());
8108 if (index < range) {
8109 num_of_elements++;
8110 if (visitor) {
8111 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
8112 }
8113 }
8114 }
8115 }
8116 break;
8117 }
8118 default:
8119 UNREACHABLE();
8120 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008121 }
8122
8123 return num_of_elements;
8124}
8125
8126
8127/**
8128 * A helper function that visits elements of an Array object, and elements
8129 * on its prototypes.
8130 *
8131 * Elements on prototypes are visited first, and only elements whose indices
8132 * less than Array length are visited.
8133 *
8134 * If a ArrayConcatVisitor object is given, the visitor is called with
8135 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008136 *
8137 * The returned number of elements is an upper bound on the actual number
8138 * of elements added. If the same element occurs in more than one object
8139 * in the array's prototype chain, it will be counted more than once, but
8140 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008141 */
8142static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
8143 ArrayConcatVisitor* visitor) {
8144 uint32_t range = static_cast<uint32_t>(array->length()->Number());
8145 Handle<Object> obj = array;
8146
8147 static const int kEstimatedPrototypes = 3;
8148 List< Handle<JSObject> > objects(kEstimatedPrototypes);
8149
8150 // Visit prototype first. If an element on the prototype is shadowed by
8151 // the inheritor using the same index, the ArrayConcatVisitor visits
8152 // the prototype element before the shadowing element.
8153 // The visitor can simply overwrite the old value by new value using
8154 // the same index. This follows Array::concat semantics.
8155 while (!obj->IsNull()) {
8156 objects.Add(Handle<JSObject>::cast(obj));
8157 obj = Handle<Object>(obj->GetPrototype());
8158 }
8159
8160 uint32_t nof_elements = 0;
8161 for (int i = objects.length() - 1; i >= 0; i--) {
8162 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008163 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008164 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008165
8166 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
8167 nof_elements = JSObject::kMaxElementCount;
8168 } else {
8169 nof_elements += encountered_elements;
8170 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008171 }
8172
8173 return nof_elements;
8174}
8175
8176
8177/**
8178 * A helper function of Runtime_ArrayConcat.
8179 *
8180 * The first argument is an Array of arrays and objects. It is the
8181 * same as the arguments array of Array::concat JS function.
8182 *
8183 * If an argument is an Array object, the function visits array
8184 * elements. If an argument is not an Array object, the function
8185 * visits the object as if it is an one-element array.
8186 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008187 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008188 * non-negative number is used as new length. For example, if one
8189 * array length is 2^32 - 1, second array length is 1, the
8190 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008191 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
8192 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008193 */
8194static uint32_t IterateArguments(Handle<JSArray> arguments,
8195 ArrayConcatVisitor* visitor) {
8196 uint32_t visited_elements = 0;
8197 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8198
8199 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008200 Object *element;
8201 MaybeObject* maybe_element = arguments->GetElement(i);
8202 // This if() is not expected to fail, but we have the check in the
8203 // interest of hardening the runtime calls.
8204 if (maybe_element->ToObject(&element)) {
8205 Handle<Object> obj(element);
8206 if (obj->IsJSArray()) {
8207 Handle<JSArray> array = Handle<JSArray>::cast(obj);
8208 uint32_t len = static_cast<uint32_t>(array->length()->Number());
8209 uint32_t nof_elements =
8210 IterateArrayAndPrototypeElements(array, visitor);
8211 // Total elements of array and its prototype chain can be more than
8212 // the array length, but ArrayConcat can only concatenate at most
8213 // the array length number of elements. We use the length as an estimate
8214 // for the actual number of elements added.
8215 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
8216 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
8217 visited_elements = JSArray::kMaxElementCount;
8218 } else {
8219 visited_elements += added_elements;
8220 }
8221 if (visitor) visitor->increase_index_offset(len);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008222 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008223 if (visitor) {
8224 visitor->visit(0, obj);
8225 visitor->increase_index_offset(1);
8226 }
8227 if (visited_elements < JSArray::kMaxElementCount) {
8228 visited_elements++;
8229 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008230 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008231 }
8232 }
8233 return visited_elements;
8234}
8235
8236
8237/**
8238 * Array::concat implementation.
8239 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008240 * TODO(lrn): Fix non-compliance for very large concatenations and update to
8241 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008242 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008243static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008244 ASSERT(args.length() == 1);
8245 HandleScope handle_scope;
8246
8247 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
8248 Handle<JSArray> arguments(arg_arrays);
8249
8250 // Pass 1: estimate the number of elements of the result
8251 // (it could be more than real numbers if prototype has elements).
8252 uint32_t result_length = 0;
8253 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8254
8255 { AssertNoAllocation nogc;
8256 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008257 Object* obj;
8258 MaybeObject* maybe_object = arguments->GetElement(i);
8259 // This if() is not expected to fail, but we have the check in the
8260 // interest of hardening the runtime calls.
8261 if (maybe_object->ToObject(&obj)) {
8262 uint32_t length_estimate;
8263 if (obj->IsJSArray()) {
8264 length_estimate =
8265 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
8266 } else {
8267 length_estimate = 1;
8268 }
8269 if (JSObject::kMaxElementCount - result_length < length_estimate) {
8270 result_length = JSObject::kMaxElementCount;
8271 break;
8272 }
8273 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008274 }
8275 }
8276 }
8277
8278 // Allocate an empty array, will set length and content later.
8279 Handle<JSArray> result = Factory::NewJSArray(0);
8280
8281 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
8282 // If estimated number of elements is more than half of length, a
8283 // fixed array (fast case) is more time and space-efficient than a
8284 // dictionary.
8285 bool fast_case = (estimate_nof_elements * 2) >= result_length;
8286
8287 Handle<FixedArray> storage;
8288 if (fast_case) {
8289 // The backing storage array must have non-existing elements to
8290 // preserve holes across concat operations.
8291 storage = Factory::NewFixedArrayWithHoles(result_length);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008292 Handle<Map> fast_map =
8293 Factory::GetFastElementsMap(Handle<Map>(result->map()));
8294 result->set_map(*fast_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008295 } else {
8296 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8297 uint32_t at_least_space_for = estimate_nof_elements +
8298 (estimate_nof_elements >> 2);
8299 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008300 Factory::NewNumberDictionary(at_least_space_for));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008301 Handle<Map> slow_map =
8302 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
8303 result->set_map(*slow_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008304 }
8305
8306 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
8307
8308 ArrayConcatVisitor visitor(storage, result_length, fast_case);
8309
8310 IterateArguments(arguments, &visitor);
8311
8312 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008313 // Please note the storage might have changed in the visitor.
8314 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008315
8316 return *result;
8317}
8318
8319
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008320// This will not allocate (flatten the string), but it may run
8321// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008322static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008323 NoHandleAllocation ha;
8324 ASSERT(args.length() == 1);
8325
8326 CONVERT_CHECKED(String, string, args[0]);
8327 StringInputBuffer buffer(string);
8328 while (buffer.has_more()) {
8329 uint16_t character = buffer.GetNext();
8330 PrintF("%c", character);
8331 }
8332 return string;
8333}
8334
ager@chromium.org5ec48922009-05-05 07:25:34 +00008335// Moves all own elements of an object, that are below a limit, to positions
8336// starting at zero. All undefined values are placed after non-undefined values,
8337// and are followed by non-existing element. Does not change the length
8338// property.
8339// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008340static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008341 ASSERT(args.length() == 2);
8342 CONVERT_CHECKED(JSObject, object, args[0]);
8343 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8344 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008345}
8346
8347
8348// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008349static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008350 ASSERT(args.length() == 2);
8351 CONVERT_CHECKED(JSArray, from, args[0]);
8352 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008353 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008354 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008355 if (new_elements->map() == Heap::fixed_array_map() ||
8356 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008357 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008358 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008359 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008360 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008361 Object* new_map;
8362 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008363 to->set_map(Map::cast(new_map));
8364 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008365 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008366 Object* obj;
8367 { MaybeObject* maybe_obj = from->ResetElements();
8368 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8369 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008370 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008371 return to;
8372}
8373
8374
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008375// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008376static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008377 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008378 CONVERT_CHECKED(JSObject, object, args[0]);
8379 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008380 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008381 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008382 } else if (object->IsJSArray()) {
8383 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008384 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008385 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008386 }
8387}
8388
8389
lrn@chromium.org303ada72010-10-27 09:33:13 +00008390static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008391 HandleScope handle_scope;
8392
8393 ASSERT_EQ(3, args.length());
8394
ager@chromium.orgac091b72010-05-05 07:34:42 +00008395 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008396 Handle<Object> key1 = args.at<Object>(1);
8397 Handle<Object> key2 = args.at<Object>(2);
8398
8399 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008400 if (!key1->ToArrayIndex(&index1)
8401 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008402 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008403 }
8404
ager@chromium.orgac091b72010-05-05 07:34:42 +00008405 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8406 Handle<Object> tmp1 = GetElement(jsobject, index1);
8407 Handle<Object> tmp2 = GetElement(jsobject, index2);
8408
8409 SetElement(jsobject, index1, tmp2);
8410 SetElement(jsobject, index2, tmp1);
8411
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008412 return Heap::undefined_value();
8413}
8414
8415
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008416// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008417// might have elements. Can either return keys (positive integers) or
8418// intervals (pair of a negative integer (-start-1) followed by a
8419// positive (length)) or undefined values.
8420// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008421static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008422 ASSERT(args.length() == 2);
8423 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008424 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008425 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008426 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008427 // Create an array and get all the keys into it, then remove all the
8428 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008429 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008430 int keys_length = keys->length();
8431 for (int i = 0; i < keys_length; i++) {
8432 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008433 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008434 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008435 // Zap invalid keys.
8436 keys->set_undefined(i);
8437 }
8438 }
8439 return *Factory::NewJSArrayWithElements(keys);
8440 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008441 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008442 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8443 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008444 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008445 uint32_t actual_length =
8446 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008447 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008448 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008449 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008450 single_interval->set(1, *length_object);
8451 return *Factory::NewJSArrayWithElements(single_interval);
8452 }
8453}
8454
8455
8456// DefineAccessor takes an optional final argument which is the
8457// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8458// to the way accessors are implemented, it is set for both the getter
8459// and setter on the first call to DefineAccessor and ignored on
8460// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008461static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008462 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8463 // Compute attributes.
8464 PropertyAttributes attributes = NONE;
8465 if (args.length() == 5) {
8466 CONVERT_CHECKED(Smi, attrs, args[4]);
8467 int value = attrs->value();
8468 // Only attribute bits should be set.
8469 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8470 attributes = static_cast<PropertyAttributes>(value);
8471 }
8472
8473 CONVERT_CHECKED(JSObject, obj, args[0]);
8474 CONVERT_CHECKED(String, name, args[1]);
8475 CONVERT_CHECKED(Smi, flag, args[2]);
8476 CONVERT_CHECKED(JSFunction, fun, args[3]);
8477 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8478}
8479
8480
lrn@chromium.org303ada72010-10-27 09:33:13 +00008481static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008482 ASSERT(args.length() == 3);
8483 CONVERT_CHECKED(JSObject, obj, args[0]);
8484 CONVERT_CHECKED(String, name, args[1]);
8485 CONVERT_CHECKED(Smi, flag, args[2]);
8486 return obj->LookupAccessor(name, flag->value() == 0);
8487}
8488
8489
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008490#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008491static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008492 ASSERT(args.length() == 0);
8493 return Execution::DebugBreakHelper();
8494}
8495
8496
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008497// Helper functions for wrapping and unwrapping stack frame ids.
8498static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008499 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008500 return Smi::FromInt(id >> 2);
8501}
8502
8503
8504static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8505 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8506}
8507
8508
8509// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008510// args[0]: debug event listener function to set or null or undefined for
8511// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008512// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008513static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008514 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008515 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8516 args[0]->IsUndefined() ||
8517 args[0]->IsNull());
8518 Handle<Object> callback = args.at<Object>(0);
8519 Handle<Object> data = args.at<Object>(1);
8520 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008521
8522 return Heap::undefined_value();
8523}
8524
8525
lrn@chromium.org303ada72010-10-27 09:33:13 +00008526static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008527 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008528 StackGuard::DebugBreak();
8529 return Heap::undefined_value();
8530}
8531
8532
lrn@chromium.org303ada72010-10-27 09:33:13 +00008533static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8534 LookupResult* result,
8535 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008536 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008537 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008538 case NORMAL:
8539 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008540 if (value->IsTheHole()) {
8541 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008542 }
8543 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008544 case FIELD:
8545 value =
8546 JSObject::cast(
8547 result->holder())->FastPropertyAt(result->GetFieldIndex());
8548 if (value->IsTheHole()) {
8549 return Heap::undefined_value();
8550 }
8551 return value;
8552 case CONSTANT_FUNCTION:
8553 return result->GetConstantFunction();
8554 case CALLBACKS: {
8555 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008556 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008557 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008558 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008559 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008560 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008561 ASSERT(maybe_value->IsException());
8562 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008563 Top::clear_pending_exception();
8564 if (caught_exception != NULL) {
8565 *caught_exception = true;
8566 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008567 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008568 }
8569 return value;
8570 } else {
8571 return Heap::undefined_value();
8572 }
8573 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008574 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008575 case MAP_TRANSITION:
8576 case CONSTANT_TRANSITION:
8577 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008578 return Heap::undefined_value();
8579 default:
8580 UNREACHABLE();
8581 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008582 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008583 return Heap::undefined_value();
8584}
8585
8586
ager@chromium.org32912102009-01-16 10:38:43 +00008587// Get debugger related details for an object property.
8588// args[0]: object holding property
8589// args[1]: name of the property
8590//
8591// The array returned contains the following information:
8592// 0: Property value
8593// 1: Property details
8594// 2: Property value is exception
8595// 3: Getter function if defined
8596// 4: Setter function if defined
8597// Items 2-4 are only filled if the property has either a getter or a setter
8598// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008599static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008600 HandleScope scope;
8601
8602 ASSERT(args.length() == 2);
8603
8604 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8605 CONVERT_ARG_CHECKED(String, name, 1);
8606
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008607 // Make sure to set the current context to the context before the debugger was
8608 // entered (if the debugger is entered). The reason for switching context here
8609 // is that for some property lookups (accessors and interceptors) callbacks
8610 // into the embedding application can occour, and the embedding application
8611 // could have the assumption that its own global context is the current
8612 // context and not some internal debugger context.
8613 SaveContext save;
8614 if (Debug::InDebugger()) {
8615 Top::set_context(*Debug::debugger_entry()->GetContext());
8616 }
8617
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008618 // Skip the global proxy as it has no properties and always delegates to the
8619 // real global object.
8620 if (obj->IsJSGlobalProxy()) {
8621 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8622 }
8623
8624
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008625 // Check if the name is trivially convertible to an index and get the element
8626 // if so.
8627 uint32_t index;
8628 if (name->AsArrayIndex(&index)) {
8629 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008630 Object* element_or_char;
8631 { MaybeObject* maybe_element_or_char =
8632 Runtime::GetElementOrCharAt(obj, index);
8633 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8634 return maybe_element_or_char;
8635 }
8636 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008637 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008638 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8639 return *Factory::NewJSArrayWithElements(details);
8640 }
8641
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008642 // Find the number of objects making up this.
8643 int length = LocalPrototypeChainLength(*obj);
8644
8645 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008646 Handle<JSObject> jsproto = obj;
8647 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008648 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008649 jsproto->LocalLookup(*name, &result);
8650 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008651 // LookupResult is not GC safe as it holds raw object pointers.
8652 // GC can happen later in this code so put the required fields into
8653 // local variables using handles when required for later use.
8654 PropertyType result_type = result.type();
8655 Handle<Object> result_callback_obj;
8656 if (result_type == CALLBACKS) {
8657 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8658 }
8659 Smi* property_details = result.GetPropertyDetails().AsSmi();
8660 // DebugLookupResultValue can cause GC so details from LookupResult needs
8661 // to be copied to handles before this.
8662 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008663 Object* raw_value;
8664 { MaybeObject* maybe_raw_value =
8665 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8666 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8667 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008668 Handle<Object> value(raw_value);
8669
8670 // If the callback object is a fixed array then it contains JavaScript
8671 // getter and/or setter.
8672 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8673 result_callback_obj->IsFixedArray();
8674 Handle<FixedArray> details =
8675 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8676 details->set(0, *value);
8677 details->set(1, property_details);
8678 if (hasJavaScriptAccessors) {
8679 details->set(2,
8680 caught_exception ? Heap::true_value()
8681 : Heap::false_value());
8682 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8683 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8684 }
8685
8686 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008687 }
8688 if (i < length - 1) {
8689 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8690 }
8691 }
8692
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008693 return Heap::undefined_value();
8694}
8695
8696
lrn@chromium.org303ada72010-10-27 09:33:13 +00008697static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008698 HandleScope scope;
8699
8700 ASSERT(args.length() == 2);
8701
8702 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8703 CONVERT_ARG_CHECKED(String, name, 1);
8704
8705 LookupResult result;
8706 obj->Lookup(*name, &result);
8707 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008708 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008709 }
8710 return Heap::undefined_value();
8711}
8712
8713
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008714// Return the property type calculated from the property details.
8715// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008716static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008717 ASSERT(args.length() == 1);
8718 CONVERT_CHECKED(Smi, details, args[0]);
8719 PropertyType type = PropertyDetails(details).type();
8720 return Smi::FromInt(static_cast<int>(type));
8721}
8722
8723
8724// Return the property attribute calculated from the property details.
8725// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008726static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008727 ASSERT(args.length() == 1);
8728 CONVERT_CHECKED(Smi, details, args[0]);
8729 PropertyAttributes attributes = PropertyDetails(details).attributes();
8730 return Smi::FromInt(static_cast<int>(attributes));
8731}
8732
8733
8734// Return the property insertion index calculated from the property details.
8735// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008736static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008737 ASSERT(args.length() == 1);
8738 CONVERT_CHECKED(Smi, details, args[0]);
8739 int index = PropertyDetails(details).index();
8740 return Smi::FromInt(index);
8741}
8742
8743
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008744// Return property value from named interceptor.
8745// args[0]: object
8746// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008747static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008748 HandleScope scope;
8749 ASSERT(args.length() == 2);
8750 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8751 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8752 CONVERT_ARG_CHECKED(String, name, 1);
8753
8754 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008755 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008756}
8757
8758
8759// Return element value from indexed interceptor.
8760// args[0]: object
8761// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008762static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8763 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008764 HandleScope scope;
8765 ASSERT(args.length() == 2);
8766 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8767 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8768 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8769
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008770 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008771}
8772
8773
lrn@chromium.org303ada72010-10-27 09:33:13 +00008774static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008775 ASSERT(args.length() >= 1);
8776 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008777 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008778 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008779 return Top::Throw(Heap::illegal_execution_state_symbol());
8780 }
8781
8782 return Heap::true_value();
8783}
8784
8785
lrn@chromium.org303ada72010-10-27 09:33:13 +00008786static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008787 HandleScope scope;
8788 ASSERT(args.length() == 1);
8789
8790 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008791 Object* result;
8792 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8793 if (!maybe_result->ToObject(&result)) return maybe_result;
8794 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008795
8796 // Count all frames which are relevant to debugging stack trace.
8797 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008798 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008799 if (id == StackFrame::NO_ID) {
8800 // If there is no JavaScript stack frame count is 0.
8801 return Smi::FromInt(0);
8802 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008803 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8804 return Smi::FromInt(n);
8805}
8806
8807
8808static const int kFrameDetailsFrameIdIndex = 0;
8809static const int kFrameDetailsReceiverIndex = 1;
8810static const int kFrameDetailsFunctionIndex = 2;
8811static const int kFrameDetailsArgumentCountIndex = 3;
8812static const int kFrameDetailsLocalCountIndex = 4;
8813static const int kFrameDetailsSourcePositionIndex = 5;
8814static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008815static const int kFrameDetailsAtReturnIndex = 7;
8816static const int kFrameDetailsDebuggerFrameIndex = 8;
8817static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008818
8819// Return an array with frame details
8820// args[0]: number: break id
8821// args[1]: number: frame index
8822//
8823// The array returned contains the following information:
8824// 0: Frame id
8825// 1: Receiver
8826// 2: Function
8827// 3: Argument count
8828// 4: Local count
8829// 5: Source position
8830// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008831// 7: Is at return
8832// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008833// Arguments name, value
8834// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008835// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00008836static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008837 HandleScope scope;
8838 ASSERT(args.length() == 2);
8839
8840 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008841 Object* check;
8842 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8843 if (!maybe_check->ToObject(&check)) return maybe_check;
8844 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008845 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8846
8847 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008848 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008849 if (id == StackFrame::NO_ID) {
8850 // If there are no JavaScript stack frames return undefined.
8851 return Heap::undefined_value();
8852 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008853 int count = 0;
8854 JavaScriptFrameIterator it(id);
8855 for (; !it.done(); it.Advance()) {
8856 if (count == index) break;
8857 count++;
8858 }
8859 if (it.done()) return Heap::undefined_value();
8860
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008861 bool is_optimized_frame =
8862 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
8863
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008864 // Traverse the saved contexts chain to find the active context for the
8865 // selected frame.
8866 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008867 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008868 save = save->prev();
8869 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008870 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008871
8872 // Get the frame id.
8873 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8874
8875 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008876 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008877
8878 // Check for constructor frame.
8879 bool constructor = it.frame()->IsConstructor();
8880
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008881 // Get scope info and read from it for local variable information.
8882 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008883 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008884 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008885
8886 // Get the context.
8887 Handle<Context> context(Context::cast(it.frame()->context()));
8888
8889 // Get the locals names and values into a temporary array.
8890 //
8891 // TODO(1240907): Hide compiler-introduced stack variables
8892 // (e.g. .result)? For users of the debugger, they will probably be
8893 // confusing.
8894 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008895
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008896 // Fill in the names of the locals.
8897 for (int i = 0; i < info.NumberOfLocals(); i++) {
8898 locals->set(i * 2, *info.LocalName(i));
8899 }
8900
8901 // Fill in the values of the locals.
8902 for (int i = 0; i < info.NumberOfLocals(); i++) {
8903 if (is_optimized_frame) {
8904 // If we are inspecting an optimized frame use undefined as the
8905 // value for all locals.
8906 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00008907 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008908 // for locals in optimized frames.
8909 locals->set(i * 2 + 1, Heap::undefined_value());
8910 } else if (i < info.number_of_stack_slots()) {
8911 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008912 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8913 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008914 // Traverse the context chain to the function context as all local
8915 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008916 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008917 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008918 context = Handle<Context>(context->previous());
8919 }
8920 ASSERT(context->is_function_context());
8921 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008922 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008923 }
8924 }
8925
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008926 // Check whether this frame is positioned at return. If not top
8927 // frame or if the frame is optimized it cannot be at a return.
8928 bool at_return = false;
8929 if (!is_optimized_frame && index == 0) {
8930 at_return = Debug::IsBreakAtReturn(it.frame());
8931 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008932
8933 // If positioned just before return find the value to be returned and add it
8934 // to the frame information.
8935 Handle<Object> return_value = Factory::undefined_value();
8936 if (at_return) {
8937 StackFrameIterator it2;
8938 Address internal_frame_sp = NULL;
8939 while (!it2.done()) {
8940 if (it2.frame()->is_internal()) {
8941 internal_frame_sp = it2.frame()->sp();
8942 } else {
8943 if (it2.frame()->is_java_script()) {
8944 if (it2.frame()->id() == it.frame()->id()) {
8945 // The internal frame just before the JavaScript frame contains the
8946 // value to return on top. A debug break at return will create an
8947 // internal frame to store the return value (eax/rax/r0) before
8948 // entering the debug break exit frame.
8949 if (internal_frame_sp != NULL) {
8950 return_value =
8951 Handle<Object>(Memory::Object_at(internal_frame_sp));
8952 break;
8953 }
8954 }
8955 }
8956
8957 // Indicate that the previous frame was not an internal frame.
8958 internal_frame_sp = NULL;
8959 }
8960 it2.Advance();
8961 }
8962 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008963
8964 // Now advance to the arguments adapter frame (if any). It contains all
8965 // the provided parameters whereas the function frame always have the number
8966 // of arguments matching the functions parameters. The rest of the
8967 // information (except for what is collected above) is the same.
8968 it.AdvanceToArgumentsFrame();
8969
8970 // Find the number of arguments to fill. At least fill the number of
8971 // parameters for the function and fill more if more parameters are provided.
8972 int argument_count = info.number_of_parameters();
8973 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8974 argument_count = it.frame()->GetProvidedParametersCount();
8975 }
8976
8977 // Calculate the size of the result.
8978 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008979 2 * (argument_count + info.NumberOfLocals()) +
8980 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008981 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8982
8983 // Add the frame id.
8984 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8985
8986 // Add the function (same as in function frame).
8987 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8988
8989 // Add the arguments count.
8990 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8991
8992 // Add the locals count
8993 details->set(kFrameDetailsLocalCountIndex,
8994 Smi::FromInt(info.NumberOfLocals()));
8995
8996 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008997 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008998 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8999 } else {
9000 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
9001 }
9002
9003 // Add the constructor information.
9004 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
9005
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009006 // Add the at return information.
9007 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
9008
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009009 // Add information on whether this frame is invoked in the debugger context.
9010 details->set(kFrameDetailsDebuggerFrameIndex,
9011 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
9012
9013 // Fill the dynamic part.
9014 int details_index = kFrameDetailsFirstDynamicIndex;
9015
9016 // Add arguments name and value.
9017 for (int i = 0; i < argument_count; i++) {
9018 // Name of the argument.
9019 if (i < info.number_of_parameters()) {
9020 details->set(details_index++, *info.parameter_name(i));
9021 } else {
9022 details->set(details_index++, Heap::undefined_value());
9023 }
9024
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009025 // Parameter value. If we are inspecting an optimized frame, use
9026 // undefined as the value.
9027 //
9028 // TODO(3141533): We should be able to get the actual parameter
9029 // value for optimized frames.
9030 if (!is_optimized_frame &&
9031 (i < it.frame()->GetProvidedParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009032 details->set(details_index++, it.frame()->GetParameter(i));
9033 } else {
9034 details->set(details_index++, Heap::undefined_value());
9035 }
9036 }
9037
9038 // Add locals name and value from the temporary copy from the function frame.
9039 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9040 details->set(details_index++, locals->get(i));
9041 }
9042
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009043 // Add the value being returned.
9044 if (at_return) {
9045 details->set(details_index++, *return_value);
9046 }
9047
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009048 // Add the receiver (same as in function frame).
9049 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9050 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
9051 Handle<Object> receiver(it.frame()->receiver());
9052 if (!receiver->IsJSObject()) {
9053 // If the receiver is NOT a JSObject we have hit an optimization
9054 // where a value object is not converted into a wrapped JS objects.
9055 // To hide this optimization from the debugger, we wrap the receiver
9056 // by creating correct wrapper object based on the calling frame's
9057 // global context.
9058 it.Advance();
9059 Handle<Context> calling_frames_global_context(
9060 Context::cast(Context::cast(it.frame()->context())->global_context()));
9061 receiver = Factory::ToObject(receiver, calling_frames_global_context);
9062 }
9063 details->set(kFrameDetailsReceiverIndex, *receiver);
9064
9065 ASSERT_EQ(details_size, details_index);
9066 return *Factory::NewJSArrayWithElements(details);
9067}
9068
9069
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009070// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009071static bool CopyContextLocalsToScopeObject(
ager@chromium.orgb5737492010-07-15 09:29:43 +00009072 Handle<SerializedScopeInfo> serialized_scope_info,
9073 ScopeInfo<>& scope_info,
9074 Handle<Context> context,
9075 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009076 // Fill all context locals to the context extension.
9077 for (int i = Context::MIN_CONTEXT_SLOTS;
9078 i < scope_info.number_of_context_slots();
9079 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009080 int context_index = serialized_scope_info->ContextSlotIndex(
9081 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009082
9083 // Don't include the arguments shadow (.arguments) context variable.
9084 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009085 RETURN_IF_EMPTY_HANDLE_VALUE(
9086 SetProperty(scope_object,
9087 scope_info.context_slot_name(i),
9088 Handle<Object>(context->get(context_index)), NONE),
9089 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009090 }
9091 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009092
9093 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009094}
9095
9096
9097// Create a plain JSObject which materializes the local scope for the specified
9098// frame.
9099static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
9100 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009101 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009102 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9103 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009104
9105 // Allocate and initialize a JSObject with all the arguments, stack locals
9106 // heap locals and extension properties of the debugged function.
9107 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
9108
9109 // First fill all parameters.
9110 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009111 RETURN_IF_EMPTY_HANDLE_VALUE(
9112 SetProperty(local_scope,
9113 scope_info.parameter_name(i),
9114 Handle<Object>(frame->GetParameter(i)), NONE),
9115 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009116 }
9117
9118 // Second fill all stack locals.
9119 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009120 RETURN_IF_EMPTY_HANDLE_VALUE(
9121 SetProperty(local_scope,
9122 scope_info.stack_slot_name(i),
9123 Handle<Object>(frame->GetExpression(i)), NONE),
9124 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009125 }
9126
9127 // Third fill all context locals.
9128 Handle<Context> frame_context(Context::cast(frame->context()));
9129 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009130 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9131 function_context, local_scope)) {
9132 return Handle<JSObject>();
9133 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009134
9135 // Finally copy any properties from the function context extension. This will
9136 // be variables introduced by eval.
9137 if (function_context->closure() == *function) {
9138 if (function_context->has_extension() &&
9139 !function_context->IsGlobalContext()) {
9140 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009141 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009142 for (int i = 0; i < keys->length(); i++) {
9143 // Names of variables introduced by eval are strings.
9144 ASSERT(keys->get(i)->IsString());
9145 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009146 RETURN_IF_EMPTY_HANDLE_VALUE(
9147 SetProperty(local_scope, key, GetProperty(ext, key), NONE),
9148 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009149 }
9150 }
9151 }
9152 return local_scope;
9153}
9154
9155
9156// Create a plain JSObject which materializes the closure content for the
9157// context.
9158static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
9159 ASSERT(context->is_function_context());
9160
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009161 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009162 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9163 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009164
9165 // Allocate and initialize a JSObject with all the content of theis function
9166 // closure.
9167 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
9168
9169 // Check whether the arguments shadow object exists.
9170 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00009171 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
9172 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009173 if (arguments_shadow_index >= 0) {
9174 // In this case all the arguments are available in the arguments shadow
9175 // object.
9176 Handle<JSObject> arguments_shadow(
9177 JSObject::cast(context->get(arguments_shadow_index)));
9178 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009179 // We don't expect exception-throwing getters on the arguments shadow.
9180 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009181 RETURN_IF_EMPTY_HANDLE_VALUE(
9182 SetProperty(closure_scope,
9183 scope_info.parameter_name(i),
9184 Handle<Object>(element),
9185 NONE),
9186 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009187 }
9188 }
9189
9190 // Fill all context locals to the context extension.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009191 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9192 context, closure_scope)) {
9193 return Handle<JSObject>();
9194 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009195
9196 // Finally copy any properties from the function context extension. This will
9197 // be variables introduced by eval.
9198 if (context->has_extension()) {
9199 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009200 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009201 for (int i = 0; i < keys->length(); i++) {
9202 // Names of variables introduced by eval are strings.
9203 ASSERT(keys->get(i)->IsString());
9204 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009205 RETURN_IF_EMPTY_HANDLE_VALUE(
9206 SetProperty(closure_scope, key, GetProperty(ext, key), NONE),
9207 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009208 }
9209 }
9210
9211 return closure_scope;
9212}
9213
9214
9215// Iterate over the actual scopes visible from a stack frame. All scopes are
9216// backed by an actual context except the local scope, which is inserted
9217// "artifically" in the context chain.
9218class ScopeIterator {
9219 public:
9220 enum ScopeType {
9221 ScopeTypeGlobal = 0,
9222 ScopeTypeLocal,
9223 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009224 ScopeTypeClosure,
9225 // Every catch block contains an implicit with block (its parameter is
9226 // a JSContextExtensionObject) that extends current scope with a variable
9227 // holding exception object. Such with blocks are treated as scopes of their
9228 // own type.
9229 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009230 };
9231
9232 explicit ScopeIterator(JavaScriptFrame* frame)
9233 : frame_(frame),
9234 function_(JSFunction::cast(frame->function())),
9235 context_(Context::cast(frame->context())),
9236 local_done_(false),
9237 at_local_(false) {
9238
9239 // Check whether the first scope is actually a local scope.
9240 if (context_->IsGlobalContext()) {
9241 // If there is a stack slot for .result then this local scope has been
9242 // created for evaluating top level code and it is not a real local scope.
9243 // Checking for the existence of .result seems fragile, but the scope info
9244 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009245 int index = function_->shared()->scope_info()->
9246 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009247 at_local_ = index < 0;
9248 } else if (context_->is_function_context()) {
9249 at_local_ = true;
9250 }
9251 }
9252
9253 // More scopes?
9254 bool Done() { return context_.is_null(); }
9255
9256 // Move to the next scope.
9257 void Next() {
9258 // If at a local scope mark the local scope as passed.
9259 if (at_local_) {
9260 at_local_ = false;
9261 local_done_ = true;
9262
9263 // If the current context is not associated with the local scope the
9264 // current context is the next real scope, so don't move to the next
9265 // context in this case.
9266 if (context_->closure() != *function_) {
9267 return;
9268 }
9269 }
9270
9271 // The global scope is always the last in the chain.
9272 if (context_->IsGlobalContext()) {
9273 context_ = Handle<Context>();
9274 return;
9275 }
9276
9277 // Move to the next context.
9278 if (context_->is_function_context()) {
9279 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9280 } else {
9281 context_ = Handle<Context>(context_->previous());
9282 }
9283
9284 // If passing the local scope indicate that the current scope is now the
9285 // local scope.
9286 if (!local_done_ &&
9287 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9288 at_local_ = true;
9289 }
9290 }
9291
9292 // Return the type of the current scope.
9293 int Type() {
9294 if (at_local_) {
9295 return ScopeTypeLocal;
9296 }
9297 if (context_->IsGlobalContext()) {
9298 ASSERT(context_->global()->IsGlobalObject());
9299 return ScopeTypeGlobal;
9300 }
9301 if (context_->is_function_context()) {
9302 return ScopeTypeClosure;
9303 }
9304 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009305 // Current scope is either an explicit with statement or a with statement
9306 // implicitely generated for a catch block.
9307 // If the extension object here is a JSContextExtensionObject then
9308 // current with statement is one frome a catch block otherwise it's a
9309 // regular with statement.
9310 if (context_->extension()->IsJSContextExtensionObject()) {
9311 return ScopeTypeCatch;
9312 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009313 return ScopeTypeWith;
9314 }
9315
9316 // Return the JavaScript object with the content of the current scope.
9317 Handle<JSObject> ScopeObject() {
9318 switch (Type()) {
9319 case ScopeIterator::ScopeTypeGlobal:
9320 return Handle<JSObject>(CurrentContext()->global());
9321 break;
9322 case ScopeIterator::ScopeTypeLocal:
9323 // Materialize the content of the local scope into a JSObject.
9324 return MaterializeLocalScope(frame_);
9325 break;
9326 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009327 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009328 // Return the with object.
9329 return Handle<JSObject>(CurrentContext()->extension());
9330 break;
9331 case ScopeIterator::ScopeTypeClosure:
9332 // Materialize the content of the closure scope into a JSObject.
9333 return MaterializeClosure(CurrentContext());
9334 break;
9335 }
9336 UNREACHABLE();
9337 return Handle<JSObject>();
9338 }
9339
9340 // Return the context for this scope. For the local context there might not
9341 // be an actual context.
9342 Handle<Context> CurrentContext() {
9343 if (at_local_ && context_->closure() != *function_) {
9344 return Handle<Context>();
9345 }
9346 return context_;
9347 }
9348
9349#ifdef DEBUG
9350 // Debug print of the content of the current scope.
9351 void DebugPrint() {
9352 switch (Type()) {
9353 case ScopeIterator::ScopeTypeGlobal:
9354 PrintF("Global:\n");
9355 CurrentContext()->Print();
9356 break;
9357
9358 case ScopeIterator::ScopeTypeLocal: {
9359 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009360 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009361 scope_info.Print();
9362 if (!CurrentContext().is_null()) {
9363 CurrentContext()->Print();
9364 if (CurrentContext()->has_extension()) {
9365 Handle<JSObject> extension =
9366 Handle<JSObject>(CurrentContext()->extension());
9367 if (extension->IsJSContextExtensionObject()) {
9368 extension->Print();
9369 }
9370 }
9371 }
9372 break;
9373 }
9374
9375 case ScopeIterator::ScopeTypeWith: {
9376 PrintF("With:\n");
9377 Handle<JSObject> extension =
9378 Handle<JSObject>(CurrentContext()->extension());
9379 extension->Print();
9380 break;
9381 }
9382
ager@chromium.orga1645e22009-09-09 19:27:10 +00009383 case ScopeIterator::ScopeTypeCatch: {
9384 PrintF("Catch:\n");
9385 Handle<JSObject> extension =
9386 Handle<JSObject>(CurrentContext()->extension());
9387 extension->Print();
9388 break;
9389 }
9390
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009391 case ScopeIterator::ScopeTypeClosure: {
9392 PrintF("Closure:\n");
9393 CurrentContext()->Print();
9394 if (CurrentContext()->has_extension()) {
9395 Handle<JSObject> extension =
9396 Handle<JSObject>(CurrentContext()->extension());
9397 if (extension->IsJSContextExtensionObject()) {
9398 extension->Print();
9399 }
9400 }
9401 break;
9402 }
9403
9404 default:
9405 UNREACHABLE();
9406 }
9407 PrintF("\n");
9408 }
9409#endif
9410
9411 private:
9412 JavaScriptFrame* frame_;
9413 Handle<JSFunction> function_;
9414 Handle<Context> context_;
9415 bool local_done_;
9416 bool at_local_;
9417
9418 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9419};
9420
9421
lrn@chromium.org303ada72010-10-27 09:33:13 +00009422static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009423 HandleScope scope;
9424 ASSERT(args.length() == 2);
9425
9426 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009427 Object* check;
9428 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9429 if (!maybe_check->ToObject(&check)) return maybe_check;
9430 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009431 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9432
9433 // Get the frame where the debugging is performed.
9434 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9435 JavaScriptFrameIterator it(id);
9436 JavaScriptFrame* frame = it.frame();
9437
9438 // Count the visible scopes.
9439 int n = 0;
9440 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9441 n++;
9442 }
9443
9444 return Smi::FromInt(n);
9445}
9446
9447
9448static const int kScopeDetailsTypeIndex = 0;
9449static const int kScopeDetailsObjectIndex = 1;
9450static const int kScopeDetailsSize = 2;
9451
9452// Return an array with scope details
9453// args[0]: number: break id
9454// args[1]: number: frame index
9455// args[2]: number: scope index
9456//
9457// The array returned contains the following information:
9458// 0: Scope type
9459// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009460static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009461 HandleScope scope;
9462 ASSERT(args.length() == 3);
9463
9464 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009465 Object* check;
9466 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9467 if (!maybe_check->ToObject(&check)) return maybe_check;
9468 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009469 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9470 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9471
9472 // Get the frame where the debugging is performed.
9473 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9474 JavaScriptFrameIterator frame_it(id);
9475 JavaScriptFrame* frame = frame_it.frame();
9476
9477 // Find the requested scope.
9478 int n = 0;
9479 ScopeIterator it(frame);
9480 for (; !it.Done() && n < index; it.Next()) {
9481 n++;
9482 }
9483 if (it.Done()) {
9484 return Heap::undefined_value();
9485 }
9486
9487 // Calculate the size of the result.
9488 int details_size = kScopeDetailsSize;
9489 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9490
9491 // Fill in scope details.
9492 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009493 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009494 RETURN_IF_EMPTY_HANDLE(scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009495 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009496
9497 return *Factory::NewJSArrayWithElements(details);
9498}
9499
9500
lrn@chromium.org303ada72010-10-27 09:33:13 +00009501static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009502 HandleScope scope;
9503 ASSERT(args.length() == 0);
9504
9505#ifdef DEBUG
9506 // Print the scopes for the top frame.
9507 StackFrameLocator locator;
9508 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9509 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9510 it.DebugPrint();
9511 }
9512#endif
9513 return Heap::undefined_value();
9514}
9515
9516
lrn@chromium.org303ada72010-10-27 09:33:13 +00009517static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009518 HandleScope scope;
9519 ASSERT(args.length() == 1);
9520
9521 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009522 Object* result;
9523 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9524 if (!maybe_result->ToObject(&result)) return maybe_result;
9525 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009526
9527 // Count all archived V8 threads.
9528 int n = 0;
9529 for (ThreadState* thread = ThreadState::FirstInUse();
9530 thread != NULL;
9531 thread = thread->Next()) {
9532 n++;
9533 }
9534
9535 // Total number of threads is current thread and archived threads.
9536 return Smi::FromInt(n + 1);
9537}
9538
9539
9540static const int kThreadDetailsCurrentThreadIndex = 0;
9541static const int kThreadDetailsThreadIdIndex = 1;
9542static const int kThreadDetailsSize = 2;
9543
9544// Return an array with thread details
9545// args[0]: number: break id
9546// args[1]: number: thread index
9547//
9548// The array returned contains the following information:
9549// 0: Is current thread?
9550// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009551static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009552 HandleScope scope;
9553 ASSERT(args.length() == 2);
9554
9555 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009556 Object* check;
9557 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9558 if (!maybe_check->ToObject(&check)) return maybe_check;
9559 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009560 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9561
9562 // Allocate array for result.
9563 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9564
9565 // Thread index 0 is current thread.
9566 if (index == 0) {
9567 // Fill the details.
9568 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9569 details->set(kThreadDetailsThreadIdIndex,
9570 Smi::FromInt(ThreadManager::CurrentId()));
9571 } else {
9572 // Find the thread with the requested index.
9573 int n = 1;
9574 ThreadState* thread = ThreadState::FirstInUse();
9575 while (index != n && thread != NULL) {
9576 thread = thread->Next();
9577 n++;
9578 }
9579 if (thread == NULL) {
9580 return Heap::undefined_value();
9581 }
9582
9583 // Fill the details.
9584 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9585 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9586 }
9587
9588 // Convert to JS array and return.
9589 return *Factory::NewJSArrayWithElements(details);
9590}
9591
9592
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009593// Sets the disable break state
9594// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009595static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009596 HandleScope scope;
9597 ASSERT(args.length() == 1);
9598 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9599 Debug::set_disable_break(disable_break);
9600 return Heap::undefined_value();
9601}
9602
9603
lrn@chromium.org303ada72010-10-27 09:33:13 +00009604static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009605 HandleScope scope;
9606 ASSERT(args.length() == 1);
9607
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009608 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9609 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009610 // Find the number of break points
9611 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9612 if (break_locations->IsUndefined()) return Heap::undefined_value();
9613 // Return array as JS array
9614 return *Factory::NewJSArrayWithElements(
9615 Handle<FixedArray>::cast(break_locations));
9616}
9617
9618
9619// Set a break point in a function
9620// args[0]: function
9621// args[1]: number: break source position (within the function source)
9622// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009623static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009624 HandleScope scope;
9625 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009626 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9627 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009628 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9629 RUNTIME_ASSERT(source_position >= 0);
9630 Handle<Object> break_point_object_arg = args.at<Object>(2);
9631
9632 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009633 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009634
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009635 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009636}
9637
9638
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009639Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9640 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009641 // Iterate the heap looking for SharedFunctionInfo generated from the
9642 // script. The inner most SharedFunctionInfo containing the source position
9643 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009644 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009645 // which is found is not compiled it is compiled and the heap is iterated
9646 // again as the compilation might create inner functions from the newly
9647 // compiled function and the actual requested break point might be in one of
9648 // these functions.
9649 bool done = false;
9650 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009651 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009652 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009653 while (!done) {
9654 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009655 for (HeapObject* obj = iterator.next();
9656 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009657 if (obj->IsSharedFunctionInfo()) {
9658 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9659 if (shared->script() == *script) {
9660 // If the SharedFunctionInfo found has the requested script data and
9661 // contains the source position it is a candidate.
9662 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009663 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009664 start_position = shared->start_position();
9665 }
9666 if (start_position <= position &&
9667 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009668 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009669 // candidate this is the new candidate.
9670 if (target.is_null()) {
9671 target_start_position = start_position;
9672 target = shared;
9673 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009674 if (target_start_position == start_position &&
9675 shared->end_position() == target->end_position()) {
9676 // If a top-level function contain only one function
9677 // declartion the source for the top-level and the function is
9678 // the same. In that case prefer the non top-level function.
9679 if (!shared->is_toplevel()) {
9680 target_start_position = start_position;
9681 target = shared;
9682 }
9683 } else if (target_start_position <= start_position &&
9684 shared->end_position() <= target->end_position()) {
9685 // This containment check includes equality as a function inside
9686 // a top-level function can share either start or end position
9687 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009688 target_start_position = start_position;
9689 target = shared;
9690 }
9691 }
9692 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009693 }
9694 }
9695 }
9696
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009697 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009698 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009699 }
9700
9701 // If the candidate found is compiled we are done. NOTE: when lazy
9702 // compilation of inner functions is introduced some additional checking
9703 // needs to be done here to compile inner functions.
9704 done = target->is_compiled();
9705 if (!done) {
9706 // If the candidate is not compiled compile it to reveal any inner
9707 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009708 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009709 }
9710 }
9711
9712 return *target;
9713}
9714
9715
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009716// Changes the state of a break point in a script and returns source position
9717// where break point was set. NOTE: Regarding performance see the NOTE for
9718// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009719// args[0]: script to set break point in
9720// args[1]: number: break source position (within the script source)
9721// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009722static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009723 HandleScope scope;
9724 ASSERT(args.length() == 3);
9725 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9726 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9727 RUNTIME_ASSERT(source_position >= 0);
9728 Handle<Object> break_point_object_arg = args.at<Object>(2);
9729
9730 // Get the script from the script wrapper.
9731 RUNTIME_ASSERT(wrapper->value()->IsScript());
9732 Handle<Script> script(Script::cast(wrapper->value()));
9733
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009734 Object* result = Runtime::FindSharedFunctionInfoInScript(
9735 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009736 if (!result->IsUndefined()) {
9737 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9738 // Find position within function. The script position might be before the
9739 // source position of the first function.
9740 int position;
9741 if (shared->start_position() > source_position) {
9742 position = 0;
9743 } else {
9744 position = source_position - shared->start_position();
9745 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009746 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9747 position += shared->start_position();
9748 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009749 }
9750 return Heap::undefined_value();
9751}
9752
9753
9754// Clear a break point
9755// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009756static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009757 HandleScope scope;
9758 ASSERT(args.length() == 1);
9759 Handle<Object> break_point_object_arg = args.at<Object>(0);
9760
9761 // Clear break point.
9762 Debug::ClearBreakPoint(break_point_object_arg);
9763
9764 return Heap::undefined_value();
9765}
9766
9767
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009768// Change the state of break on exceptions.
9769// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9770// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009771static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009772 HandleScope scope;
9773 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009774 RUNTIME_ASSERT(args[0]->IsNumber());
9775 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009776
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009777 // If the number doesn't match an enum value, the ChangeBreakOnException
9778 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009779 ExceptionBreakType type =
9780 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009781 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009782 Debug::ChangeBreakOnException(type, enable);
9783 return Heap::undefined_value();
9784}
9785
9786
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009787// Returns the state of break on exceptions
9788// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009789static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009790 HandleScope scope;
9791 ASSERT(args.length() == 1);
9792 RUNTIME_ASSERT(args[0]->IsNumber());
9793
9794 ExceptionBreakType type =
9795 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9796 bool result = Debug::IsBreakOnException(type);
9797 return Smi::FromInt(result);
9798}
9799
9800
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009801// Prepare for stepping
9802// args[0]: break id for checking execution state
9803// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009804// args[2]: number of times to perform the step, for step out it is the number
9805// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009806static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009807 HandleScope scope;
9808 ASSERT(args.length() == 3);
9809 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009810 Object* check;
9811 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9812 if (!maybe_check->ToObject(&check)) return maybe_check;
9813 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009814 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9815 return Top::Throw(Heap::illegal_argument_symbol());
9816 }
9817
9818 // Get the step action and check validity.
9819 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9820 if (step_action != StepIn &&
9821 step_action != StepNext &&
9822 step_action != StepOut &&
9823 step_action != StepInMin &&
9824 step_action != StepMin) {
9825 return Top::Throw(Heap::illegal_argument_symbol());
9826 }
9827
9828 // Get the number of steps.
9829 int step_count = NumberToInt32(args[2]);
9830 if (step_count < 1) {
9831 return Top::Throw(Heap::illegal_argument_symbol());
9832 }
9833
ager@chromium.orga1645e22009-09-09 19:27:10 +00009834 // Clear all current stepping setup.
9835 Debug::ClearStepping();
9836
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009837 // Prepare step.
9838 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9839 return Heap::undefined_value();
9840}
9841
9842
9843// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009844static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009845 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009846 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009847 Debug::ClearStepping();
9848 return Heap::undefined_value();
9849}
9850
9851
9852// Creates a copy of the with context chain. The copy of the context chain is
9853// is linked to the function context supplied.
9854static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9855 Handle<Context> function_context) {
9856 // At the bottom of the chain. Return the function context to link to.
9857 if (context_chain->is_function_context()) {
9858 return function_context;
9859 }
9860
9861 // Recursively copy the with contexts.
9862 Handle<Context> previous(context_chain->previous());
9863 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009864 Handle<Context> context = CopyWithContextChain(function_context, previous);
9865 return Factory::NewWithContext(context,
9866 extension,
9867 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009868}
9869
9870
9871// Helper function to find or create the arguments object for
9872// Runtime_DebugEvaluate.
9873static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9874 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009875 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009876 const ScopeInfo<>* sinfo,
9877 Handle<Context> function_context) {
9878 // Try to find the value of 'arguments' to pass as parameter. If it is not
9879 // found (that is the debugged function does not reference 'arguments' and
9880 // does not support eval) then create an 'arguments' object.
9881 int index;
9882 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009883 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009884 if (index != -1) {
9885 return Handle<Object>(frame->GetExpression(index));
9886 }
9887 }
9888
9889 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009890 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009891 if (index != -1) {
9892 return Handle<Object>(function_context->get(index));
9893 }
9894 }
9895
9896 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009897 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9898 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009899
9900 AssertNoAllocation no_gc;
9901 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009902 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009903 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009904 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009905 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009906 return arguments;
9907}
9908
9909
9910// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009911// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009912// extension part has all the parameters and locals of the function on the
9913// stack frame. A function which calls eval with the code to evaluate is then
9914// compiled in this context and called in this context. As this context
9915// replaces the context of the function on the stack frame a new (empty)
9916// function is created as well to be used as the closure for the context.
9917// This function and the context acts as replacements for the function on the
9918// stack frame presenting the same view of the values of parameters and
9919// local variables as if the piece of JavaScript was evaluated at the point
9920// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009921static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009922 HandleScope scope;
9923
9924 // Check the execution state and decode arguments frame and source to be
9925 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009926 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009927 Object* check_result;
9928 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9929 if (!maybe_check_result->ToObject(&check_result)) {
9930 return maybe_check_result;
9931 }
9932 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009933 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9934 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009935 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009936 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009937
9938 // Handle the processing of break.
9939 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009940
9941 // Get the frame where the debugging is performed.
9942 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9943 JavaScriptFrameIterator it(id);
9944 JavaScriptFrame* frame = it.frame();
9945 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009946 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009947 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009948
9949 // Traverse the saved contexts chain to find the active context for the
9950 // selected frame.
9951 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009952 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009953 save = save->prev();
9954 }
9955 ASSERT(save != NULL);
9956 SaveContext savex;
9957 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009958
9959 // Create the (empty) function replacing the function on the stack frame for
9960 // the purpose of evaluating in the context created below. It is important
9961 // that this function does not describe any parameters and local variables
9962 // in the context. If it does then this will cause problems with the lookup
9963 // in Context::Lookup, where context slots for parameters and local variables
9964 // are looked at before the extension object.
9965 Handle<JSFunction> go_between =
9966 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9967 go_between->set_context(function->context());
9968#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009969 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009970 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9971 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9972#endif
9973
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009974 // Materialize the content of the local scope into a JSObject.
9975 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009976 RETURN_IF_EMPTY_HANDLE(local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009977
9978 // Allocate a new context for the debug evaluation and set the extension
9979 // object build.
9980 Handle<Context> context =
9981 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009982 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009983 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009984 Handle<Context> frame_context(Context::cast(frame->context()));
9985 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009986 context = CopyWithContextChain(frame_context, context);
9987
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009988 if (additional_context->IsJSObject()) {
9989 context = Factory::NewWithContext(context,
9990 Handle<JSObject>::cast(additional_context), false);
9991 }
9992
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009993 // Wrap the evaluation statement in a new function compiled in the newly
9994 // created context. The function has one parameter which has to be called
9995 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009996 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009997 // function(arguments,__source__) {return eval(__source__);}
9998 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009999 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010000 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010001 Handle<String> function_source =
10002 Factory::NewStringFromAscii(Vector<const char>(source_str,
10003 source_str_length));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010004
10005 // Currently, the eval code will be executed in non-strict mode,
10006 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010007 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010008 Compiler::CompileEval(function_source,
10009 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010010 context->IsGlobalContext(),
10011 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010012 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010013 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010014 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010015
10016 // Invoke the result of the compilation to get the evaluation function.
10017 bool has_pending_exception;
10018 Handle<Object> receiver(frame->receiver());
10019 Handle<Object> evaluation_function =
10020 Execution::Call(compiled_function, receiver, 0, NULL,
10021 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010022 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010023
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010024 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
10025 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010026
10027 // Invoke the evaluation function and return the result.
10028 const int argc = 2;
10029 Object** argv[argc] = { arguments.location(),
10030 Handle<Object>::cast(source).location() };
10031 Handle<Object> result =
10032 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10033 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010034 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010035
10036 // Skip the global proxy as it has no properties and always delegates to the
10037 // real global object.
10038 if (result->IsJSGlobalProxy()) {
10039 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10040 }
10041
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010042 return *result;
10043}
10044
10045
lrn@chromium.org303ada72010-10-27 09:33:13 +000010046static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010047 HandleScope scope;
10048
10049 // Check the execution state and decode arguments frame and source to be
10050 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010051 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010052 Object* check_result;
10053 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10054 if (!maybe_check_result->ToObject(&check_result)) {
10055 return maybe_check_result;
10056 }
10057 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010058 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010059 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010060 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010061
10062 // Handle the processing of break.
10063 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010064
10065 // Enter the top context from before the debugger was invoked.
10066 SaveContext save;
10067 SaveContext* top = &save;
10068 while (top != NULL && *top->context() == *Debug::debug_context()) {
10069 top = top->prev();
10070 }
10071 if (top != NULL) {
10072 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010073 }
10074
10075 // Get the global context now set to the top context from before the
10076 // debugger was invoked.
10077 Handle<Context> context = Top::global_context();
10078
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010079 bool is_global = true;
10080
10081 if (additional_context->IsJSObject()) {
10082 // Create a function context first, than put 'with' context on top of it.
10083 Handle<JSFunction> go_between = Factory::NewFunction(
10084 Factory::empty_string(), Factory::undefined_value());
10085 go_between->set_context(*context);
10086 context =
10087 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
10088 context->set_extension(JSObject::cast(*additional_context));
10089 is_global = false;
10090 }
10091
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010092 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010093 // Currently, the eval code will be executed in non-strict mode,
10094 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010095 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010096 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010097 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010098 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010099 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
10100 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010101
10102 // Invoke the result of the compilation to get the evaluation function.
10103 bool has_pending_exception;
10104 Handle<Object> receiver = Top::global();
10105 Handle<Object> result =
10106 Execution::Call(compiled_function, receiver, 0, NULL,
10107 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010108 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010109 return *result;
10110}
10111
10112
lrn@chromium.org303ada72010-10-27 09:33:13 +000010113static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010114 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +000010115 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010116
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010117 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010118 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010119
10120 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010121 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010122 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10123 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10124 // because using
10125 // instances->set(i, *GetScriptWrapper(script))
10126 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10127 // already have deferenced the instances handle.
10128 Handle<JSValue> wrapper = GetScriptWrapper(script);
10129 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010130 }
10131
10132 // Return result as a JS array.
10133 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
10134 Handle<JSArray>::cast(result)->SetContent(*instances);
10135 return *result;
10136}
10137
10138
10139// Helper function used by Runtime_DebugReferencedBy below.
10140static int DebugReferencedBy(JSObject* target,
10141 Object* instance_filter, int max_references,
10142 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010143 JSFunction* arguments_function) {
10144 NoHandleAllocation ha;
10145 AssertNoAllocation no_alloc;
10146
10147 // Iterate the heap.
10148 int count = 0;
10149 JSObject* last = NULL;
10150 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010151 HeapObject* heap_obj = NULL;
10152 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010153 (max_references == 0 || count < max_references)) {
10154 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010155 if (heap_obj->IsJSObject()) {
10156 // Skip context extension objects and argument arrays as these are
10157 // checked in the context of functions using them.
10158 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010159 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010160 obj->map()->constructor() == arguments_function) {
10161 continue;
10162 }
10163
10164 // Check if the JS object has a reference to the object looked for.
10165 if (obj->ReferencesObject(target)) {
10166 // Check instance filter if supplied. This is normally used to avoid
10167 // references from mirror objects (see Runtime_IsInPrototypeChain).
10168 if (!instance_filter->IsUndefined()) {
10169 Object* V = obj;
10170 while (true) {
10171 Object* prototype = V->GetPrototype();
10172 if (prototype->IsNull()) {
10173 break;
10174 }
10175 if (instance_filter == prototype) {
10176 obj = NULL; // Don't add this object.
10177 break;
10178 }
10179 V = prototype;
10180 }
10181 }
10182
10183 if (obj != NULL) {
10184 // Valid reference found add to instance array if supplied an update
10185 // count.
10186 if (instances != NULL && count < instances_size) {
10187 instances->set(count, obj);
10188 }
10189 last = obj;
10190 count++;
10191 }
10192 }
10193 }
10194 }
10195
10196 // Check for circular reference only. This can happen when the object is only
10197 // referenced from mirrors and has a circular reference in which case the
10198 // object is not really alive and would have been garbage collected if not
10199 // referenced from the mirror.
10200 if (count == 1 && last == target) {
10201 count = 0;
10202 }
10203
10204 // Return the number of referencing objects found.
10205 return count;
10206}
10207
10208
10209// Scan the heap for objects with direct references to an object
10210// args[0]: the object to find references to
10211// args[1]: constructor function for instances to exclude (Mirror)
10212// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010213static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010214 ASSERT(args.length() == 3);
10215
10216 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010217 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010218
10219 // Check parameters.
10220 CONVERT_CHECKED(JSObject, target, args[0]);
10221 Object* instance_filter = args[1];
10222 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10223 instance_filter->IsJSObject());
10224 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10225 RUNTIME_ASSERT(max_references >= 0);
10226
10227 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010228 JSObject* arguments_boilerplate =
10229 Top::context()->global_context()->arguments_boilerplate();
10230 JSFunction* arguments_function =
10231 JSFunction::cast(arguments_boilerplate->map()->constructor());
10232
10233 // Get the number of referencing objects.
10234 int count;
10235 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010236 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010237
10238 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010239 Object* object;
10240 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10241 if (!maybe_object->ToObject(&object)) return maybe_object;
10242 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010243 FixedArray* instances = FixedArray::cast(object);
10244
10245 // Fill the referencing objects.
10246 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010247 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010248
10249 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010250 Object* result;
10251 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10252 Top::context()->global_context()->array_function());
10253 if (!maybe_result->ToObject(&result)) return maybe_result;
10254 }
10255 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010256 return result;
10257}
10258
10259
10260// Helper function used by Runtime_DebugConstructedBy below.
10261static int DebugConstructedBy(JSFunction* constructor, int max_references,
10262 FixedArray* instances, int instances_size) {
10263 AssertNoAllocation no_alloc;
10264
10265 // Iterate the heap.
10266 int count = 0;
10267 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010268 HeapObject* heap_obj = NULL;
10269 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010270 (max_references == 0 || count < max_references)) {
10271 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010272 if (heap_obj->IsJSObject()) {
10273 JSObject* obj = JSObject::cast(heap_obj);
10274 if (obj->map()->constructor() == constructor) {
10275 // Valid reference found add to instance array if supplied an update
10276 // count.
10277 if (instances != NULL && count < instances_size) {
10278 instances->set(count, obj);
10279 }
10280 count++;
10281 }
10282 }
10283 }
10284
10285 // Return the number of referencing objects found.
10286 return count;
10287}
10288
10289
10290// Scan the heap for objects constructed by a specific function.
10291// args[0]: the constructor to find instances of
10292// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010293static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010294 ASSERT(args.length() == 2);
10295
10296 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010297 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010298
10299 // Check parameters.
10300 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10301 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10302 RUNTIME_ASSERT(max_references >= 0);
10303
10304 // Get the number of referencing objects.
10305 int count;
10306 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10307
10308 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010309 Object* object;
10310 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10311 if (!maybe_object->ToObject(&object)) return maybe_object;
10312 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010313 FixedArray* instances = FixedArray::cast(object);
10314
10315 // Fill the referencing objects.
10316 count = DebugConstructedBy(constructor, max_references, instances, count);
10317
10318 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010319 Object* result;
10320 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10321 Top::context()->global_context()->array_function());
10322 if (!maybe_result->ToObject(&result)) return maybe_result;
10323 }
10324 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010325 return result;
10326}
10327
10328
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010329// Find the effective prototype object as returned by __proto__.
10330// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010331static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010332 ASSERT(args.length() == 1);
10333
10334 CONVERT_CHECKED(JSObject, obj, args[0]);
10335
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010336 // Use the __proto__ accessor.
10337 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010338}
10339
10340
lrn@chromium.org303ada72010-10-27 09:33:13 +000010341static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010342 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010343 CPU::DebugBreak();
10344 return Heap::undefined_value();
10345}
10346
10347
lrn@chromium.org303ada72010-10-27 09:33:13 +000010348static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010349#ifdef DEBUG
10350 HandleScope scope;
10351 ASSERT(args.length() == 1);
10352 // Get the function and make sure it is compiled.
10353 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010354 Handle<SharedFunctionInfo> shared(func->shared());
10355 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010356 return Failure::Exception();
10357 }
10358 func->code()->PrintLn();
10359#endif // DEBUG
10360 return Heap::undefined_value();
10361}
ager@chromium.org9085a012009-05-11 19:22:57 +000010362
10363
lrn@chromium.org303ada72010-10-27 09:33:13 +000010364static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010365#ifdef DEBUG
10366 HandleScope scope;
10367 ASSERT(args.length() == 1);
10368 // Get the function and make sure it is compiled.
10369 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010370 Handle<SharedFunctionInfo> shared(func->shared());
10371 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010372 return Failure::Exception();
10373 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010374 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010375#endif // DEBUG
10376 return Heap::undefined_value();
10377}
10378
10379
lrn@chromium.org303ada72010-10-27 09:33:13 +000010380static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010381 NoHandleAllocation ha;
10382 ASSERT(args.length() == 1);
10383
10384 CONVERT_CHECKED(JSFunction, f, args[0]);
10385 return f->shared()->inferred_name();
10386}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010387
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010388
10389static int FindSharedFunctionInfosForScript(Script* script,
10390 FixedArray* buffer) {
10391 AssertNoAllocation no_allocations;
10392
10393 int counter = 0;
10394 int buffer_size = buffer->length();
10395 HeapIterator iterator;
10396 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10397 ASSERT(obj != NULL);
10398 if (!obj->IsSharedFunctionInfo()) {
10399 continue;
10400 }
10401 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10402 if (shared->script() != script) {
10403 continue;
10404 }
10405 if (counter < buffer_size) {
10406 buffer->set(counter, shared);
10407 }
10408 counter++;
10409 }
10410 return counter;
10411}
10412
10413// For a script finds all SharedFunctionInfo's in the heap that points
10414// to this script. Returns JSArray of SharedFunctionInfo wrapped
10415// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010416static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010417 Arguments args) {
10418 ASSERT(args.length() == 1);
10419 HandleScope scope;
10420 CONVERT_CHECKED(JSValue, script_value, args[0]);
10421
10422 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10423
10424 const int kBufferSize = 32;
10425
10426 Handle<FixedArray> array;
10427 array = Factory::NewFixedArray(kBufferSize);
10428 int number = FindSharedFunctionInfosForScript(*script, *array);
10429 if (number > kBufferSize) {
10430 array = Factory::NewFixedArray(number);
10431 FindSharedFunctionInfosForScript(*script, *array);
10432 }
10433
10434 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10435 result->set_length(Smi::FromInt(number));
10436
10437 LiveEdit::WrapSharedFunctionInfos(result);
10438
10439 return *result;
10440}
10441
10442// For a script calculates compilation information about all its functions.
10443// The script source is explicitly specified by the second argument.
10444// The source of the actual script is not used, however it is important that
10445// all generated code keeps references to this particular instance of script.
10446// Returns a JSArray of compilation infos. The array is ordered so that
10447// each function with all its descendant is always stored in a continues range
10448// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010449static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010450 ASSERT(args.length() == 2);
10451 HandleScope scope;
10452 CONVERT_CHECKED(JSValue, script, args[0]);
10453 CONVERT_ARG_CHECKED(String, source, 1);
10454 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10455
10456 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10457
10458 if (Top::has_pending_exception()) {
10459 return Failure::Exception();
10460 }
10461
10462 return result;
10463}
10464
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010465// Changes the source of the script to a new_source.
10466// If old_script_name is provided (i.e. is a String), also creates a copy of
10467// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010468static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010469 ASSERT(args.length() == 3);
10470 HandleScope scope;
10471 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10472 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010473 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010474
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010475 CONVERT_CHECKED(Script, original_script_pointer,
10476 original_script_value->value());
10477 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010478
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010479 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10480 new_source,
10481 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010482
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010483 if (old_script->IsScript()) {
10484 Handle<Script> script_handle(Script::cast(old_script));
10485 return *(GetScriptWrapper(script_handle));
10486 } else {
10487 return Heap::null_value();
10488 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010489}
10490
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010491
10492static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10493 ASSERT(args.length() == 1);
10494 HandleScope scope;
10495 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10496 return LiveEdit::FunctionSourceUpdated(shared_info);
10497}
10498
10499
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010500// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010501static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010502 ASSERT(args.length() == 2);
10503 HandleScope scope;
10504 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10505 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10506
ager@chromium.orgac091b72010-05-05 07:34:42 +000010507 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010508}
10509
10510// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010511static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010512 ASSERT(args.length() == 2);
10513 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010514 Handle<Object> function_object(args[0]);
10515 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010516
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010517 if (function_object->IsJSValue()) {
10518 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10519 if (script_object->IsJSValue()) {
10520 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10521 script_object = Handle<Object>(script);
10522 }
10523
10524 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10525 } else {
10526 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10527 // and we check it in this function.
10528 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010529
10530 return Heap::undefined_value();
10531}
10532
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010533
10534// In a code of a parent function replaces original function as embedded object
10535// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010536static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010537 ASSERT(args.length() == 3);
10538 HandleScope scope;
10539
10540 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10541 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10542 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10543
10544 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10545 subst_wrapper);
10546
10547 return Heap::undefined_value();
10548}
10549
10550
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010551// Updates positions of a shared function info (first parameter) according
10552// to script source change. Text change is described in second parameter as
10553// array of groups of 3 numbers:
10554// (change_begin, change_end, change_end_new_position).
10555// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010556static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010557 ASSERT(args.length() == 2);
10558 HandleScope scope;
10559 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10560 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10561
ager@chromium.orgac091b72010-05-05 07:34:42 +000010562 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010563}
10564
10565
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010566// For array of SharedFunctionInfo's (each wrapped in JSValue)
10567// checks that none of them have activations on stacks (of any thread).
10568// Returns array of the same length with corresponding results of
10569// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010570static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010571 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010572 HandleScope scope;
10573 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010574 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010575
ager@chromium.org357bf652010-04-12 11:30:10 +000010576 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010577}
10578
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010579// Compares 2 strings line-by-line, then token-wise and returns diff in form
10580// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
10581// of diff chunks.
10582static MaybeObject* Runtime_LiveEditCompareStrings(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010583 ASSERT(args.length() == 2);
10584 HandleScope scope;
10585 CONVERT_ARG_CHECKED(String, s1, 0);
10586 CONVERT_ARG_CHECKED(String, s2, 1);
10587
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010588 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010589}
10590
10591
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010592
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010593// A testing entry. Returns statement position which is the closest to
10594// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010595static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010596 ASSERT(args.length() == 2);
10597 HandleScope scope;
10598 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10599 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10600
10601 Handle<Code> code(function->code());
10602
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010603 if (code->kind() != Code::FUNCTION &&
10604 code->kind() != Code::OPTIMIZED_FUNCTION) {
10605 return Heap::undefined_value();
10606 }
10607
10608 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010609 int closest_pc = 0;
10610 int distance = kMaxInt;
10611 while (!it.done()) {
10612 int statement_position = static_cast<int>(it.rinfo()->data());
10613 // Check if this break point is closer that what was previously found.
10614 if (source_position <= statement_position &&
10615 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010616 closest_pc =
10617 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010618 distance = statement_position - source_position;
10619 // Check whether we can't get any closer.
10620 if (distance == 0) break;
10621 }
10622 it.next();
10623 }
10624
10625 return Smi::FromInt(closest_pc);
10626}
10627
10628
ager@chromium.org357bf652010-04-12 11:30:10 +000010629// Calls specified function with or without entering the debugger.
10630// This is used in unit tests to run code as if debugger is entered or simply
10631// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010632static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010633 ASSERT(args.length() == 2);
10634 HandleScope scope;
10635 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10636 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10637
10638 Handle<Object> result;
10639 bool pending_exception;
10640 {
10641 if (without_debugger) {
10642 result = Execution::Call(function, Top::global(), 0, NULL,
10643 &pending_exception);
10644 } else {
10645 EnterDebugger enter_debugger;
10646 result = Execution::Call(function, Top::global(), 0, NULL,
10647 &pending_exception);
10648 }
10649 }
10650 if (!pending_exception) {
10651 return *result;
10652 } else {
10653 return Failure::Exception();
10654 }
10655}
10656
10657
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010658// Sets a v8 flag.
10659static MaybeObject* Runtime_SetFlags(Arguments args) {
10660 CONVERT_CHECKED(String, arg, args[0]);
10661 SmartPointer<char> flags =
10662 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
10663 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
10664 return Heap::undefined_value();
10665}
10666
10667
10668// Performs a GC.
10669// Presently, it only does a full GC.
10670static MaybeObject* Runtime_CollectGarbage(Arguments args) {
10671 Heap::CollectAllGarbage(true);
10672 return Heap::undefined_value();
10673}
10674
10675
10676// Gets the current heap usage.
10677static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
10678 int usage = static_cast<int>(Heap::SizeOfObjects());
10679 if (!Smi::IsValid(usage)) {
10680 return *Factory::NewNumberFromInt(usage);
10681 }
10682 return Smi::FromInt(usage);
10683}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010684#endif // ENABLE_DEBUGGER_SUPPORT
10685
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010686
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010687#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org303ada72010-10-27 09:33:13 +000010688static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010689 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010690 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010691
10692 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010693 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10694 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010695 return Heap::undefined_value();
10696}
10697
10698
lrn@chromium.org303ada72010-10-27 09:33:13 +000010699static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010700 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010701 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010702
10703 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010704 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10705 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010706 return Heap::undefined_value();
10707}
10708
10709#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010710
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010711// Finds the script object from the script data. NOTE: This operation uses
10712// heap traversal to find the function generated for the source position
10713// for the requested break point. For lazily compiled functions several heap
10714// traversals might be required rendering this operation as a rather slow
10715// operation. However for setting break points which is normally done through
10716// some kind of user interaction the performance is not crucial.
10717static Handle<Object> Runtime_GetScriptFromScriptName(
10718 Handle<String> script_name) {
10719 // Scan the heap for Script objects to find the script with the requested
10720 // script data.
10721 Handle<Script> script;
10722 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010723 HeapObject* obj = NULL;
10724 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010725 // If a script is found check if it has the script data requested.
10726 if (obj->IsScript()) {
10727 if (Script::cast(obj)->name()->IsString()) {
10728 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
10729 script = Handle<Script>(Script::cast(obj));
10730 }
10731 }
10732 }
10733 }
10734
10735 // If no script with the requested script data is found return undefined.
10736 if (script.is_null()) return Factory::undefined_value();
10737
10738 // Return the script found.
10739 return GetScriptWrapper(script);
10740}
10741
10742
10743// Get the script object from script data. NOTE: Regarding performance
10744// see the NOTE for GetScriptFromScriptData.
10745// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000010746static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010747 HandleScope scope;
10748
10749 ASSERT(args.length() == 1);
10750
10751 CONVERT_CHECKED(String, script_name, args[0]);
10752
10753 // Find the requested script.
10754 Handle<Object> result =
10755 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10756 return *result;
10757}
10758
10759
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010760// Determines whether the given stack frame should be displayed in
10761// a stack trace. The caller is the error constructor that asked
10762// for the stack trace to be collected. The first time a construct
10763// call to this function is encountered it is skipped. The seen_caller
10764// in/out parameter is used to remember if the caller has been seen
10765// yet.
10766static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10767 bool* seen_caller) {
10768 // Only display JS frames.
10769 if (!raw_frame->is_java_script())
10770 return false;
10771 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10772 Object* raw_fun = frame->function();
10773 // Not sure when this can happen but skip it just in case.
10774 if (!raw_fun->IsJSFunction())
10775 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010776 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010777 *seen_caller = true;
10778 return false;
10779 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010780 // Skip all frames until we've seen the caller. Also, skip the most
10781 // obvious builtin calls. Some builtin calls (such as Number.ADD
10782 // which is invoked using 'call') are very difficult to recognize
10783 // so we're leaving them in for now.
10784 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010785}
10786
10787
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010788// Collect the raw data for a stack trace. Returns an array of 4
10789// element segments each containing a receiver, function, code and
10790// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010791static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010792 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010793 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010794 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10795
10796 HandleScope scope;
10797
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010798 limit = Max(limit, 0); // Ensure that limit is not negative.
10799 int initial_size = Min(limit, 10);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010800 Handle<JSArray> result = Factory::NewJSArray(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010801
10802 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010803 // If the caller parameter is a function we skip frames until we're
10804 // under it before starting to collect.
10805 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010806 int cursor = 0;
10807 int frames_seen = 0;
10808 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010809 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010810 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010811 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010812 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010813 List<FrameSummary> frames(3); // Max 2 levels of inlining.
10814 frame->Summarize(&frames);
10815 for (int i = frames.length() - 1; i >= 0; i--) {
10816 Handle<Object> recv = frames[i].receiver();
10817 Handle<JSFunction> fun = frames[i].function();
10818 Handle<Code> code = frames[i].code();
10819 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
10820 FixedArray* elements = FixedArray::cast(result->elements());
10821 if (cursor + 3 < elements->length()) {
10822 elements->set(cursor++, *recv);
10823 elements->set(cursor++, *fun);
10824 elements->set(cursor++, *code);
10825 elements->set(cursor++, *offset);
10826 } else {
10827 SetElement(result, cursor++, recv);
10828 SetElement(result, cursor++, fun);
10829 SetElement(result, cursor++, code);
10830 SetElement(result, cursor++, offset);
10831 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010832 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010833 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010834 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010835 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010836
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010837 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010838 return *result;
10839}
10840
10841
ager@chromium.org3811b432009-10-28 14:53:37 +000010842// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010843static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010844 ASSERT_EQ(args.length(), 0);
10845
10846 NoHandleAllocation ha;
10847
10848 const char* version_string = v8::V8::GetVersion();
10849
10850 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10851}
10852
10853
lrn@chromium.org303ada72010-10-27 09:33:13 +000010854static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010855 ASSERT(args.length() == 2);
10856 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10857 Smi::cast(args[1])->value());
10858 Top::PrintStack();
10859 OS::Abort();
10860 UNREACHABLE();
10861 return NULL;
10862}
10863
10864
lrn@chromium.org303ada72010-10-27 09:33:13 +000010865static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010866 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010867 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010868 Object* key = args[1];
10869
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010870 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010871 Object* o = cache->get(finger_index);
10872 if (o == key) {
10873 // The fastest case: hit the same place again.
10874 return cache->get(finger_index + 1);
10875 }
10876
10877 for (int i = finger_index - 2;
10878 i >= JSFunctionResultCache::kEntriesIndex;
10879 i -= 2) {
10880 o = cache->get(i);
10881 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010882 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010883 return cache->get(i + 1);
10884 }
10885 }
10886
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010887 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010888 ASSERT(size <= cache->length());
10889
10890 for (int i = size - 2; i > finger_index; i -= 2) {
10891 o = cache->get(i);
10892 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010893 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010894 return cache->get(i + 1);
10895 }
10896 }
10897
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010898 // There is no value in the cache. Invoke the function and cache result.
10899 HandleScope scope;
10900
10901 Handle<JSFunctionResultCache> cache_handle(cache);
10902 Handle<Object> key_handle(key);
10903 Handle<Object> value;
10904 {
10905 Handle<JSFunction> factory(JSFunction::cast(
10906 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
10907 // TODO(antonm): consider passing a receiver when constructing a cache.
10908 Handle<Object> receiver(Top::global_context()->global());
10909 // This handle is nor shared, nor used later, so it's safe.
10910 Object** argv[] = { key_handle.location() };
10911 bool pending_exception = false;
10912 value = Execution::Call(factory,
10913 receiver,
10914 1,
10915 argv,
10916 &pending_exception);
10917 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010918 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010919
10920#ifdef DEBUG
10921 cache_handle->JSFunctionResultCacheVerify();
10922#endif
10923
10924 // Function invocation may have cleared the cache. Reread all the data.
10925 finger_index = cache_handle->finger_index();
10926 size = cache_handle->size();
10927
10928 // If we have spare room, put new data into it, otherwise evict post finger
10929 // entry which is likely to be the least recently used.
10930 int index = -1;
10931 if (size < cache_handle->length()) {
10932 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
10933 index = size;
10934 } else {
10935 index = finger_index + JSFunctionResultCache::kEntrySize;
10936 if (index == cache_handle->length()) {
10937 index = JSFunctionResultCache::kEntriesIndex;
10938 }
10939 }
10940
10941 ASSERT(index % 2 == 0);
10942 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
10943 ASSERT(index < cache_handle->length());
10944
10945 cache_handle->set(index, *key_handle);
10946 cache_handle->set(index + 1, *value);
10947 cache_handle->set_finger_index(index);
10948
10949#ifdef DEBUG
10950 cache_handle->JSFunctionResultCacheVerify();
10951#endif
10952
10953 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010954}
10955
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000010956
10957static MaybeObject* Runtime_NewMessageObject(Arguments args) {
10958 HandleScope scope;
10959 CONVERT_ARG_CHECKED(String, type, 0);
10960 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
10961 return *Factory::NewJSMessageObject(type,
10962 arguments,
10963 0,
10964 0,
10965 Factory::undefined_value(),
10966 Factory::undefined_value(),
10967 Factory::undefined_value());
10968}
10969
10970
10971static MaybeObject* Runtime_MessageGetType(Arguments args) {
10972 CONVERT_CHECKED(JSMessageObject, message, args[0]);
10973 return message->type();
10974}
10975
10976
10977static MaybeObject* Runtime_MessageGetArguments(Arguments args) {
10978 CONVERT_CHECKED(JSMessageObject, message, args[0]);
10979 return message->arguments();
10980}
10981
10982
10983static MaybeObject* Runtime_MessageGetStartPosition(Arguments args) {
10984 CONVERT_CHECKED(JSMessageObject, message, args[0]);
10985 return Smi::FromInt(message->start_position());
10986}
10987
10988
10989static MaybeObject* Runtime_MessageGetScript(Arguments args) {
10990 CONVERT_CHECKED(JSMessageObject, message, args[0]);
10991 return message->script();
10992}
10993
10994
kasper.lund44510672008-07-25 07:37:58 +000010995#ifdef DEBUG
10996// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10997// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010998static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010999 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011000 HandleScope scope;
11001 Handle<JSArray> result = Factory::NewJSArray(0);
11002 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011003 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011004#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011005 { \
11006 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011007 Handle<String> name; \
11008 /* Inline runtime functions have an underscore in front of the name. */ \
11009 if (inline_runtime_functions) { \
11010 name = Factory::NewStringFromAscii( \
11011 Vector<const char>("_" #Name, StrLength("_" #Name))); \
11012 } else { \
11013 name = Factory::NewStringFromAscii( \
11014 Vector<const char>(#Name, StrLength(#Name))); \
11015 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011016 Handle<JSArray> pair = Factory::NewJSArray(0); \
11017 SetElement(pair, 0, name); \
11018 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
11019 SetElement(result, index++, pair); \
11020 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011021 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011022 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011023 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011024 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011025 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011026#undef ADD_ENTRY
11027 return *result;
11028}
kasper.lund44510672008-07-25 07:37:58 +000011029#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011030
11031
lrn@chromium.org303ada72010-10-27 09:33:13 +000011032static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011033 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011034 CONVERT_CHECKED(String, format, args[0]);
11035 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011036 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011037 Logger::LogRuntime(chars, elms);
11038 return Heap::undefined_value();
11039}
11040
11041
lrn@chromium.org303ada72010-10-27 09:33:13 +000011042static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011043 UNREACHABLE(); // implemented as macro in the parser
11044 return NULL;
11045}
11046
11047
11048// ----------------------------------------------------------------------------
11049// Implementation of Runtime
11050
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011051#define F(name, number_of_args, result_size) \
11052 { Runtime::k##name, Runtime::RUNTIME, #name, \
11053 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011054
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011055
11056#define I(name, number_of_args, result_size) \
11057 { Runtime::kInline##name, Runtime::INLINE, \
11058 "_" #name, NULL, number_of_args, result_size },
11059
11060Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011061 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011062 INLINE_FUNCTION_LIST(I)
11063 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011064};
11065
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011066
lrn@chromium.org303ada72010-10-27 09:33:13 +000011067MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011068 ASSERT(dictionary != NULL);
11069 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11070 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011071 Object* name_symbol;
11072 { MaybeObject* maybe_name_symbol =
11073 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
11074 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11075 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011076 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011077 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11078 String::cast(name_symbol),
11079 Smi::FromInt(i),
11080 PropertyDetails(NONE, NORMAL));
11081 if (!maybe_dictionary->ToObject(&dictionary)) {
11082 // Non-recoverable failure. Calling code must restart heap
11083 // initialization.
11084 return maybe_dictionary;
11085 }
11086 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011087 }
11088 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011089}
11090
11091
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011092Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11093 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
11094 if (entry != kNotFound) {
11095 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
11096 int function_index = Smi::cast(smi_index)->value();
11097 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011098 }
11099 return NULL;
11100}
11101
11102
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011103Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
11104 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11105}
11106
11107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011108void Runtime::PerformGC(Object* result) {
11109 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011110 if (failure->IsRetryAfterGC()) {
11111 // Try to do a garbage collection; ignore it if it fails. The C
11112 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000011113 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011114 } else {
11115 // Handle last resort GC and make sure to allow future allocations
11116 // to grow the heap without causing GCs (if possible).
11117 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000011118 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011119 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011120}
11121
11122
11123} } // namespace v8::internal