blob: 7b90469e12ad3c1ffb9fc22db2007eb23fc56213 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000045#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000046#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000047#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000049#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000050#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000052#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000053#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000054#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000055#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000056#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
kasperl@chromium.org71affb52009-05-26 05:44:31 +000058namespace v8 {
59namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060
61
ager@chromium.org3e875802009-06-29 08:26:34 +000062#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000063 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65// Cast the given object to a value of the specified type and store
66// it in a variable with the given name. If the object is not of the
67// expected type call IllegalOperation and return.
68#define CONVERT_CHECKED(Type, name, obj) \
69 RUNTIME_ASSERT(obj->Is##Type()); \
70 Type* name = Type::cast(obj);
71
72#define CONVERT_ARG_CHECKED(Type, name, index) \
73 RUNTIME_ASSERT(args[index]->Is##Type()); \
74 Handle<Type> name = args.at<Type>(index);
75
kasper.lundbd3ec4e2008-07-09 11:06:54 +000076// Cast the given object to a boolean and store it in a variable with
77// the given name. If the object is not a boolean call IllegalOperation
78// and return.
79#define CONVERT_BOOLEAN_CHECKED(name, obj) \
80 RUNTIME_ASSERT(obj->IsBoolean()); \
81 bool name = (obj)->IsTrue();
82
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000083// Cast the given object to a Smi and store its value in an int variable
84// with the given name. If the object is not a Smi call IllegalOperation
85// and return.
86#define CONVERT_SMI_CHECKED(name, obj) \
87 RUNTIME_ASSERT(obj->IsSmi()); \
88 int name = Smi::cast(obj)->value();
89
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000090// Cast the given object to a double and store it in a variable with
91// the given name. If the object is not a number (as opposed to
92// the number not-a-number) call IllegalOperation and return.
93#define CONVERT_DOUBLE_CHECKED(name, obj) \
94 RUNTIME_ASSERT(obj->IsNumber()); \
95 double name = (obj)->Number();
96
97// Call the specified converter on the object *comand store the result in
98// a variable of the specified type with the given name. If the
99// object is not a Number call IllegalOperation and return.
100#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
101 RUNTIME_ASSERT(obj->IsNumber()); \
102 type name = NumberTo##Type(obj);
103
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000105MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
106 JSObject* boilerplate) {
107 StackLimitCheck check(isolate);
108 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000110 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000111 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000113 if (!maybe_result->ToObject(&result)) return maybe_result;
114 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000115 JSObject* copy = JSObject::cast(result);
116
117 // Deep copy local properties.
118 if (copy->HasFastProperties()) {
119 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000120 for (int i = 0; i < properties->length(); i++) {
121 Object* value = properties->get(i);
122 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000123 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000124 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000125 if (!maybe_result->ToObject(&result)) return maybe_result;
126 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000127 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000128 }
129 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000130 int nof = copy->map()->inobject_properties();
131 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000132 Object* value = copy->InObjectPropertyAt(i);
133 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000134 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000135 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000136 if (!maybe_result->ToObject(&result)) return maybe_result;
137 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000138 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000139 }
140 }
141 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000142 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000143 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 if (!maybe_result->ToObject(&result)) return maybe_result;
145 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146 FixedArray* names = FixedArray::cast(result);
147 copy->GetLocalPropertyNames(names, 0);
148 for (int i = 0; i < names->length(); i++) {
149 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000150 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 // Only deep copy fields from the object literal expression.
154 // In particular, don't try to copy the length attribute of
155 // an array.
156 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000157 Object* value =
158 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000159 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000160 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000161 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000162 if (!maybe_result->ToObject(&result)) return maybe_result;
163 }
164 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000165 // Creating object copy for literals. No strict mode needed.
166 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000167 if (!maybe_result->ToObject(&result)) return maybe_result;
168 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000169 }
170 }
171 }
172
173 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000174 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000175 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000176 switch (copy->GetElementsKind()) {
177 case JSObject::FAST_ELEMENTS: {
178 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000179 if (elements->map() == heap->fixed_cow_array_map()) {
180 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000181#ifdef DEBUG
182 for (int i = 0; i < elements->length(); i++) {
183 ASSERT(!elements->get(i)->IsJSObject());
184 }
185#endif
186 } else {
187 for (int i = 0; i < elements->length(); i++) {
188 Object* value = elements->get(i);
189 if (value->IsJSObject()) {
190 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000191 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
192 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000193 if (!maybe_result->ToObject(&result)) return maybe_result;
194 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000195 elements->set(i, result);
196 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000197 }
198 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000199 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000200 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 case JSObject::DICTIONARY_ELEMENTS: {
202 NumberDictionary* element_dictionary = copy->element_dictionary();
203 int capacity = element_dictionary->Capacity();
204 for (int i = 0; i < capacity; i++) {
205 Object* k = element_dictionary->KeyAt(i);
206 if (element_dictionary->IsKey(k)) {
207 Object* value = element_dictionary->ValueAt(i);
208 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000209 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000210 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
211 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000212 if (!maybe_result->ToObject(&result)) return maybe_result;
213 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000214 element_dictionary->ValueAtPut(i, result);
215 }
216 }
217 }
218 break;
219 }
220 default:
221 UNREACHABLE();
222 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000223 }
224 return copy;
225}
226
227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000228RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000229 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000230 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000231}
232
233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000234RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000236 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000237}
238
239
ager@chromium.org236ad962008-09-25 09:45:57 +0000240static Handle<Map> ComputeObjectLiteralMap(
241 Handle<Context> context,
242 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000243 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000244 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000245 int properties_length = constant_properties->length();
246 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000247 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000248 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000249 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000250 for (int p = 0; p != properties_length; p += 2) {
251 Object* key = constant_properties->get(p);
252 uint32_t element_index = 0;
253 if (key->IsSymbol()) {
254 number_of_symbol_keys++;
255 } else if (key->ToArrayIndex(&element_index)) {
256 // An index key does not require space in the property backing store.
257 number_of_properties--;
258 } else {
259 // Bail out as a non-symbol non-index key makes caching impossible.
260 // ASSERT to make sure that the if condition after the loop is false.
261 ASSERT(number_of_symbol_keys != number_of_properties);
262 break;
263 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000265 // If we only have symbols and array indices among keys then we can
266 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000267 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000268 if ((number_of_symbol_keys == number_of_properties) &&
269 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000270 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000271 Handle<FixedArray> keys =
272 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000273 if (number_of_symbol_keys > 0) {
274 int index = 0;
275 for (int p = 0; p < properties_length; p += 2) {
276 Object* key = constant_properties->get(p);
277 if (key->IsSymbol()) {
278 keys->set(index++, key);
279 }
280 }
281 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000282 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000283 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000284 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000285 }
286 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000287 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000288 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000289 Handle<Map>(context->object_function()->initial_map()),
290 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000291}
292
293
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000294static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000295 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000296 Handle<FixedArray> literals,
297 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000298
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000299
300static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000301 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000302 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000303 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 bool should_have_fast_elements,
305 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000306 // Get the global context from the literals array. This is the
307 // context in which the function was created and we use the object
308 // function from this context to create the object literal. We do
309 // not use the object function from the current global context
310 // because this might be the object function from another context
311 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000312 Handle<Context> context =
313 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 // In case we have function literals, we want the object to be in
316 // slow properties mode for now. We don't go in the map cache because
317 // maps with constant functions can't be shared if the functions are
318 // not the same (which is the common case).
319 bool is_result_from_cache = false;
320 Handle<Map> map = has_function_literal
321 ? Handle<Map>(context->object_function()->initial_map())
322 : ComputeObjectLiteralMap(context,
323 constant_properties,
324 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000326 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000327
328 // Normalize the elements of the boilerplate to save space if needed.
329 if (!should_have_fast_elements) NormalizeElements(boilerplate);
330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 // Add the constant properties to the boilerplate.
332 int length = constant_properties->length();
333 bool should_transform =
334 !is_result_from_cache && boilerplate->HasFastProperties();
335 if (should_transform || has_function_literal) {
336 // Normalize the properties of object to avoid n^2 behavior
337 // when extending the object multiple properties. Indicate the number of
338 // properties to be added.
339 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
340 }
341
342 for (int index = 0; index < length; index +=2) {
343 Handle<Object> key(constant_properties->get(index+0), isolate);
344 Handle<Object> value(constant_properties->get(index+1), isolate);
345 if (value->IsFixedArray()) {
346 // The value contains the constant_properties of a
347 // simple object or array literal.
348 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
349 value = CreateLiteralBoilerplate(isolate, literals, array);
350 if (value.is_null()) return value;
351 }
352 Handle<Object> result;
353 uint32_t element_index = 0;
354 if (key->IsSymbol()) {
355 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
356 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000357 result = SetOwnElement(boilerplate,
358 element_index,
359 value,
360 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000362 Handle<String> name(String::cast(*key));
363 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000364 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
365 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000366 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000367 } else if (key->ToArrayIndex(&element_index)) {
368 // Array index (uint32).
369 result = SetOwnElement(boilerplate,
370 element_index,
371 value,
372 kNonStrictMode);
373 } else {
374 // Non-uint32 number.
375 ASSERT(key->IsNumber());
376 double num = key->Number();
377 char arr[100];
378 Vector<char> buffer(arr, ARRAY_SIZE(arr));
379 const char* str = DoubleToCString(num, buffer);
380 Handle<String> name =
381 isolate->factory()->NewStringFromAscii(CStrVector(str));
382 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
383 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000385 // If setting the property on the boilerplate throws an
386 // exception, the exception is converted to an empty handle in
387 // the handle based operations. In that case, we need to
388 // convert back to an exception.
389 if (result.is_null()) return result;
390 }
391
392 // Transform to fast properties if necessary. For object literals with
393 // containing function literals we defer this operation until after all
394 // computed properties have been assigned so that we can generate
395 // constant function properties.
396 if (should_transform && !has_function_literal) {
397 TransformToFastProperties(boilerplate,
398 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 }
400
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000401 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000402}
403
404
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000405static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000406 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000407 Handle<FixedArray> literals,
408 Handle<FixedArray> elements) {
409 // Create the JSArray.
410 Handle<JSFunction> constructor(
411 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000412 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 const bool is_cow =
415 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000416 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000418
419 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000420 if (is_cow) {
421#ifdef DEBUG
422 // Copy-on-write arrays must be shallow (and simple).
423 for (int i = 0; i < content->length(); i++) {
424 ASSERT(!content->get(i)->IsFixedArray());
425 }
426#endif
427 } else {
428 for (int i = 0; i < content->length(); i++) {
429 if (content->get(i)->IsFixedArray()) {
430 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000432 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
433 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000434 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000435 if (result.is_null()) return result;
436 content->set(i, *result);
437 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438 }
439 }
440
441 // Set the elements.
442 Handle<JSArray>::cast(object)->SetContent(*content);
443 return object;
444}
445
446
447static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000448 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000449 Handle<FixedArray> literals,
450 Handle<FixedArray> array) {
451 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000452 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000453 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000454 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000455 return CreateObjectLiteralBoilerplate(isolate,
456 literals,
457 elements,
458 true,
459 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000460 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000461 return CreateObjectLiteralBoilerplate(isolate,
462 literals,
463 elements,
464 false,
465 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000466 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000467 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000468 default:
469 UNREACHABLE();
470 return Handle<Object>::null();
471 }
472}
473
474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000475RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000476 // Takes a FixedArray of elements containing the literal elements of
477 // the array literal and produces JSArray with those elements.
478 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000479 // which contains the context from which to get the Array function
480 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000481 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000482 ASSERT(args.length() == 3);
483 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
484 CONVERT_SMI_CHECKED(literals_index, args[1]);
485 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000487 Handle<Object> object =
488 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000489 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000490
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000491 // Update the functions literal and return the boilerplate.
492 literals->set(literals_index, *object);
493 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000494}
495
496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000497RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000498 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000499 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000500 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
501 CONVERT_SMI_CHECKED(literals_index, args[1]);
502 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000503 CONVERT_SMI_CHECKED(flags, args[3]);
504 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
505 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000506
507 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000508 Handle<Object> boilerplate(literals->get(literals_index), isolate);
509 if (*boilerplate == isolate->heap()->undefined_value()) {
510 boilerplate = CreateObjectLiteralBoilerplate(isolate,
511 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000512 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000513 should_have_fast_elements,
514 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000515 if (boilerplate.is_null()) return Failure::Exception();
516 // Update the functions literal and return the boilerplate.
517 literals->set(literals_index, *boilerplate);
518 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000519 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000520}
521
522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000523RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000525 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000526 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
527 CONVERT_SMI_CHECKED(literals_index, args[1]);
528 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000529 CONVERT_SMI_CHECKED(flags, args[3]);
530 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
531 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000532
533 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 Handle<Object> boilerplate(literals->get(literals_index), isolate);
535 if (*boilerplate == isolate->heap()->undefined_value()) {
536 boilerplate = CreateObjectLiteralBoilerplate(isolate,
537 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000538 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 should_have_fast_elements,
540 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000541 if (boilerplate.is_null()) return Failure::Exception();
542 // Update the functions literal and return the boilerplate.
543 literals->set(literals_index, *boilerplate);
544 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000546}
547
548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000549RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000550 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000551 ASSERT(args.length() == 3);
552 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
553 CONVERT_SMI_CHECKED(literals_index, args[1]);
554 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
555
556 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000557 Handle<Object> boilerplate(literals->get(literals_index), isolate);
558 if (*boilerplate == isolate->heap()->undefined_value()) {
559 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000560 if (boilerplate.is_null()) return Failure::Exception();
561 // Update the functions literal and return the boilerplate.
562 literals->set(literals_index, *boilerplate);
563 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000564 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565}
566
567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000568RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000569 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000570 ASSERT(args.length() == 3);
571 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
572 CONVERT_SMI_CHECKED(literals_index, args[1]);
573 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
574
575 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000576 Handle<Object> boilerplate(literals->get(literals_index), isolate);
577 if (*boilerplate == isolate->heap()->undefined_value()) {
578 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000579 if (boilerplate.is_null()) return Failure::Exception();
580 // Update the functions literal and return the boilerplate.
581 literals->set(literals_index, *boilerplate);
582 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000583 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000585 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000586 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000587 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588}
589
590
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000591RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
592 ASSERT(args.length() == 2);
593 Object* handler = args[0];
594 Object* prototype = args[1];
595 Object* used_prototype =
596 (prototype->IsJSObject() || prototype->IsJSProxy()) ? prototype
597 : isolate->heap()->null_value();
598 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
599}
600
601
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000602RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000603 ASSERT(args.length() == 2);
604 CONVERT_CHECKED(String, key, args[0]);
605 Object* value = args[1];
606 // Create a catch context extension object.
607 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000608 isolate->context()->global_context()->
609 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000610 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000611 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000612 if (!maybe_object->ToObject(&object)) return maybe_object;
613 }
ager@chromium.org32912102009-01-16 10:38:43 +0000614 // Assign the exception value to the catch variable and make sure
615 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000616 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000617 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
618 JSObject::cast(object)->SetProperty(
619 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000620 if (!maybe_value->ToObject(&value)) return maybe_value;
621 }
ager@chromium.org32912102009-01-16 10:38:43 +0000622 return object;
623}
624
625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000626RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000627 NoHandleAllocation ha;
628 ASSERT(args.length() == 1);
629 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000630 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000631 return JSObject::cast(obj)->class_name();
632}
633
ager@chromium.org7c537e22008-10-16 08:43:32 +0000634
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000635RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000636 NoHandleAllocation ha;
637 ASSERT(args.length() == 2);
638 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
639 Object* O = args[0];
640 Object* V = args[1];
641 while (true) {
642 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000643 if (prototype->IsNull()) return isolate->heap()->false_value();
644 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000645 V = prototype;
646 }
647}
648
649
ager@chromium.org9085a012009-05-11 19:22:57 +0000650// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000651RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000652 NoHandleAllocation ha;
653 ASSERT(args.length() == 2);
654 CONVERT_CHECKED(JSObject, jsobject, args[0]);
655 CONVERT_CHECKED(JSObject, proto, args[1]);
656
657 // Sanity checks. The old prototype (that we are replacing) could
658 // theoretically be null, but if it is not null then check that we
659 // didn't already install a hidden prototype here.
660 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
661 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
662 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
663
664 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000665 Object* map_or_failure;
666 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
667 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
668 return maybe_map_or_failure;
669 }
670 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000671 Map* new_proto_map = Map::cast(map_or_failure);
672
lrn@chromium.org303ada72010-10-27 09:33:13 +0000673 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
674 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
675 return maybe_map_or_failure;
676 }
677 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000678 Map* new_map = Map::cast(map_or_failure);
679
680 // Set proto's prototype to be the old prototype of the object.
681 new_proto_map->set_prototype(jsobject->GetPrototype());
682 proto->set_map(new_proto_map);
683 new_proto_map->set_is_hidden_prototype();
684
685 // Set the object's prototype to proto.
686 new_map->set_prototype(proto);
687 jsobject->set_map(new_map);
688
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000689 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000690}
691
692
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000693RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000694 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000695 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000696 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000697 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000698}
699
700
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000701// Recursively traverses hidden prototypes if property is not found
702static void GetOwnPropertyImplementation(JSObject* obj,
703 String* name,
704 LookupResult* result) {
705 obj->LocalLookupRealNamedProperty(name, result);
706
707 if (!result->IsProperty()) {
708 Object* proto = obj->GetPrototype();
709 if (proto->IsJSObject() &&
710 JSObject::cast(proto)->map()->is_hidden_prototype())
711 GetOwnPropertyImplementation(JSObject::cast(proto),
712 name, result);
713 }
714}
715
716
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000717static bool CheckAccessException(LookupResult* result,
718 v8::AccessType access_type) {
719 if (result->type() == CALLBACKS) {
720 Object* callback = result->GetCallbackObject();
721 if (callback->IsAccessorInfo()) {
722 AccessorInfo* info = AccessorInfo::cast(callback);
723 bool can_access =
724 (access_type == v8::ACCESS_HAS &&
725 (info->all_can_read() || info->all_can_write())) ||
726 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
727 (access_type == v8::ACCESS_SET && info->all_can_write());
728 return can_access;
729 }
730 }
731
732 return false;
733}
734
735
736static bool CheckAccess(JSObject* obj,
737 String* name,
738 LookupResult* result,
739 v8::AccessType access_type) {
740 ASSERT(result->IsProperty());
741
742 JSObject* holder = result->holder();
743 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000744 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000745 while (true) {
746 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000747 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000748 // Access check callback denied the access, but some properties
749 // can have a special permissions which override callbacks descision
750 // (currently see v8::AccessControl).
751 break;
752 }
753
754 if (current == holder) {
755 return true;
756 }
757
758 current = JSObject::cast(current->GetPrototype());
759 }
760
761 // API callbacks can have per callback access exceptions.
762 switch (result->type()) {
763 case CALLBACKS: {
764 if (CheckAccessException(result, access_type)) {
765 return true;
766 }
767 break;
768 }
769 case INTERCEPTOR: {
770 // If the object has an interceptor, try real named properties.
771 // Overwrite the result to fetch the correct property later.
772 holder->LookupRealNamedProperty(name, result);
773 if (result->IsProperty()) {
774 if (CheckAccessException(result, access_type)) {
775 return true;
776 }
777 }
778 break;
779 }
780 default:
781 break;
782 }
783
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000784 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000785 return false;
786}
787
788
789// TODO(1095): we should traverse hidden prototype hierachy as well.
790static bool CheckElementAccess(JSObject* obj,
791 uint32_t index,
792 v8::AccessType access_type) {
793 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000794 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000795 return false;
796 }
797
798 return true;
799}
800
801
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000802// Enumerator used as indices into the array returned from GetOwnProperty
803enum PropertyDescriptorIndices {
804 IS_ACCESSOR_INDEX,
805 VALUE_INDEX,
806 GETTER_INDEX,
807 SETTER_INDEX,
808 WRITABLE_INDEX,
809 ENUMERABLE_INDEX,
810 CONFIGURABLE_INDEX,
811 DESCRIPTOR_SIZE
812};
813
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000814// Returns an array with the property description:
815// if args[1] is not a property on args[0]
816// returns undefined
817// if args[1] is a data property on args[0]
818// [false, value, Writeable, Enumerable, Configurable]
819// if args[1] is an accessor on args[0]
820// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000821RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000822 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000823 Heap* heap = isolate->heap();
824 HandleScope scope(isolate);
825 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
826 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000827 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000828 CONVERT_ARG_CHECKED(JSObject, obj, 0);
829 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000830
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000831 // This could be an element.
832 uint32_t index;
833 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000834 switch (obj->HasLocalElement(index)) {
835 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000836 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000837
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000838 case JSObject::STRING_CHARACTER_ELEMENT: {
839 // Special handling of string objects according to ECMAScript 5
840 // 15.5.5.2. Note that this might be a string object with elements
841 // other than the actual string value. This is covered by the
842 // subsequent cases.
843 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
844 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000845 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000846
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000847 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000848 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000849 elms->set(WRITABLE_INDEX, heap->false_value());
850 elms->set(ENUMERABLE_INDEX, heap->false_value());
851 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000852 return *desc;
853 }
854
855 case JSObject::INTERCEPTED_ELEMENT:
856 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000857 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000858 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000860 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 elms->set(WRITABLE_INDEX, heap->true_value());
862 elms->set(ENUMERABLE_INDEX, heap->true_value());
863 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000864 return *desc;
865 }
866
867 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000868 Handle<JSObject> holder = obj;
869 if (obj->IsJSGlobalProxy()) {
870 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000871 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000872 ASSERT(proto->IsJSGlobalObject());
873 holder = Handle<JSObject>(JSObject::cast(proto));
874 }
875 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000876 int entry = dictionary->FindEntry(index);
877 ASSERT(entry != NumberDictionary::kNotFound);
878 PropertyDetails details = dictionary->DetailsAt(entry);
879 switch (details.type()) {
880 case CALLBACKS: {
881 // This is an accessor property with getter and/or setter.
882 FixedArray* callbacks =
883 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000884 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000885 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
886 elms->set(GETTER_INDEX, callbacks->get(0));
887 }
888 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
889 elms->set(SETTER_INDEX, callbacks->get(1));
890 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000891 break;
892 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000893 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000894 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000895 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000896 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000897 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000898 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000899 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000900 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000901 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000902 default:
903 UNREACHABLE();
904 break;
905 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000906 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
907 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000908 return *desc;
909 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000910 }
911 }
912
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000913 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000914 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000915
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000916 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000917 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000918 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000919
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000920 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000921 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000922 }
923
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000924 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
925 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000926
927 bool is_js_accessor = (result.type() == CALLBACKS) &&
928 (result.GetCallbackObject()->IsFixedArray());
929
930 if (is_js_accessor) {
931 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000933
934 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
935 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
936 elms->set(GETTER_INDEX, structure->get(0));
937 }
938 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
939 elms->set(SETTER_INDEX, structure->get(1));
940 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000941 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000942 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
943 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000944
945 PropertyAttributes attrs;
946 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000947 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000948 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
949 if (!maybe_value->ToObject(&value)) return maybe_value;
950 }
951 elms->set(VALUE_INDEX, value);
952 }
953
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000954 return *desc;
955}
956
957
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000958RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000959 ASSERT(args.length() == 1);
960 CONVERT_CHECKED(JSObject, obj, args[0]);
961 return obj->PreventExtensions();
962}
963
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000964
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000965RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000966 ASSERT(args.length() == 1);
967 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000968 if (obj->IsJSGlobalProxy()) {
969 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000970 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000971 ASSERT(proto->IsJSGlobalObject());
972 obj = JSObject::cast(proto);
973 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000974 return obj->map()->is_extensible() ? isolate->heap()->true_value()
975 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000976}
977
978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000979RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000982 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
983 CONVERT_ARG_CHECKED(String, pattern, 1);
984 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000985 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
986 if (result.is_null()) return Failure::Exception();
987 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988}
989
990
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000991RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000992 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000993 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000994 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000995 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996}
997
998
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000999RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001000 ASSERT(args.length() == 1);
1001 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001002 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004}
1005
1006
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001007RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001008 ASSERT(args.length() == 2);
1009 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001011 int index = field->value();
1012 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1013 InstanceType type = templ->map()->instance_type();
1014 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1015 type == OBJECT_TEMPLATE_INFO_TYPE);
1016 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001017 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001018 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1019 } else {
1020 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1021 }
1022 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023}
1024
1025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001026RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001027 ASSERT(args.length() == 1);
1028 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001029 Map* old_map = object->map();
1030 bool needs_access_checks = old_map->is_access_check_needed();
1031 if (needs_access_checks) {
1032 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001033 Object* new_map;
1034 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1035 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1036 }
ager@chromium.org32912102009-01-16 10:38:43 +00001037
1038 Map::cast(new_map)->set_is_access_check_needed(false);
1039 object->set_map(Map::cast(new_map));
1040 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001041 return needs_access_checks ? isolate->heap()->true_value()
1042 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001043}
1044
1045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001046RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001047 ASSERT(args.length() == 1);
1048 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001049 Map* old_map = object->map();
1050 if (!old_map->is_access_check_needed()) {
1051 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001052 Object* new_map;
1053 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1054 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1055 }
ager@chromium.org32912102009-01-16 10:38:43 +00001056
1057 Map::cast(new_map)->set_is_access_check_needed(true);
1058 object->set_map(Map::cast(new_map));
1059 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001061}
1062
1063
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001064static Failure* ThrowRedeclarationError(Isolate* isolate,
1065 const char* type,
1066 Handle<String> name) {
1067 HandleScope scope(isolate);
1068 Handle<Object> type_handle =
1069 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001070 Handle<Object> args[2] = { type_handle, name };
1071 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001072 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1073 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001074}
1075
1076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001077RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001078 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001079 HandleScope scope(isolate);
1080 Handle<GlobalObject> global = Handle<GlobalObject>(
1081 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001082
ager@chromium.org3811b432009-10-28 14:53:37 +00001083 Handle<Context> context = args.at<Context>(0);
1084 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001086 StrictModeFlag strict_mode =
1087 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1088 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001089
1090 // Compute the property attributes. According to ECMA-262, section
1091 // 13, page 71, the property must be read-only and
1092 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1093 // property as read-only, so we don't either.
1094 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1095
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001096 // Traverse the name/value pairs and set the properties.
1097 int length = pairs->length();
1098 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001099 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001100 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001101 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102
1103 // We have to declare a global const property. To capture we only
1104 // assign to it when evaluating the assignment for "const x =
1105 // <expr>" the initial value is the hole.
1106 bool is_const_property = value->IsTheHole();
1107
1108 if (value->IsUndefined() || is_const_property) {
1109 // Lookup the property in the global object, and don't set the
1110 // value of the variable if the property is already there.
1111 LookupResult lookup;
1112 global->Lookup(*name, &lookup);
1113 if (lookup.IsProperty()) {
1114 // Determine if the property is local by comparing the holder
1115 // against the global object. The information will be used to
1116 // avoid throwing re-declaration errors when declaring
1117 // variables or constants that exist in the prototype chain.
1118 bool is_local = (*global == lookup.holder());
1119 // Get the property attributes and determine if the property is
1120 // read-only.
1121 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1122 bool is_read_only = (attributes & READ_ONLY) != 0;
1123 if (lookup.type() == INTERCEPTOR) {
1124 // If the interceptor says the property is there, we
1125 // just return undefined without overwriting the property.
1126 // Otherwise, we continue to setting the property.
1127 if (attributes != ABSENT) {
1128 // Check if the existing property conflicts with regards to const.
1129 if (is_local && (is_read_only || is_const_property)) {
1130 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001131 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001132 };
1133 // The property already exists without conflicting: Go to
1134 // the next declaration.
1135 continue;
1136 }
1137 // Fall-through and introduce the absent property by using
1138 // SetProperty.
1139 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001140 // For const properties, we treat a callback with this name
1141 // even in the prototype as a conflicting declaration.
1142 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001143 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001144 }
1145 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146 if (is_local && (is_read_only || is_const_property)) {
1147 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001148 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001149 }
1150 // The property already exists without conflicting: Go to
1151 // the next declaration.
1152 continue;
1153 }
1154 }
1155 } else {
1156 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001157 Handle<SharedFunctionInfo> shared =
1158 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001159 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001160 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1161 context,
1162 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 value = function;
1164 }
1165
1166 LookupResult lookup;
1167 global->LocalLookup(*name, &lookup);
1168
1169 PropertyAttributes attributes = is_const_property
1170 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1171 : base;
1172
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001173 // There's a local property that we need to overwrite because
1174 // we're either declaring a function or there's an interceptor
1175 // that claims the property is absent.
1176 //
1177 // Check for conflicting re-declarations. We cannot have
1178 // conflicting types in case of intercepted properties because
1179 // they are absent.
1180 if (lookup.IsProperty() &&
1181 (lookup.type() != INTERCEPTOR) &&
1182 (lookup.IsReadOnly() || is_const_property)) {
1183 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001184 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001185 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001186
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001187 // Safari does not allow the invocation of callback setters for
1188 // function declarations. To mimic this behavior, we do not allow
1189 // the invocation of setters for function values. This makes a
1190 // difference for global functions with the same names as event
1191 // handlers such as "function onload() {}". Firefox does call the
1192 // onload setter in those case and Safari does not. We follow
1193 // Safari for compatibility.
1194 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001195 // Do not change DONT_DELETE to false from true.
1196 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1197 attributes = static_cast<PropertyAttributes>(
1198 attributes | (lookup.GetAttributes() & DONT_DELETE));
1199 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001200 RETURN_IF_EMPTY_HANDLE(isolate,
1201 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001202 name,
1203 value,
1204 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001206 RETURN_IF_EMPTY_HANDLE(isolate,
1207 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001208 name,
1209 value,
1210 attributes,
1211 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212 }
1213 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001215 ASSERT(!isolate->has_pending_exception());
1216 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001217}
1218
1219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001220RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001221 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001222 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223
ager@chromium.org7c537e22008-10-16 08:43:32 +00001224 CONVERT_ARG_CHECKED(Context, context, 0);
1225 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001227 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001228 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001229 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001230
1231 // Declarations are always done in the function context.
1232 context = Handle<Context>(context->fcontext());
1233
1234 int index;
1235 PropertyAttributes attributes;
1236 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001237 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001238 context->Lookup(name, flags, &index, &attributes);
1239
1240 if (attributes != ABSENT) {
1241 // The name was declared before; check for conflicting
1242 // re-declarations: This is similar to the code in parser.cc in
1243 // the AstBuildingParser::Declare function.
1244 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1245 // Functions are not read-only.
1246 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1247 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001248 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249 }
1250
1251 // Initialize it if necessary.
1252 if (*initial_value != NULL) {
1253 if (index >= 0) {
1254 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001255 // the function context or the arguments object.
1256 if (holder->IsContext()) {
1257 ASSERT(holder.is_identical_to(context));
1258 if (((attributes & READ_ONLY) == 0) ||
1259 context->get(index)->IsTheHole()) {
1260 context->set(index, *initial_value);
1261 }
1262 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001263 // The holder is an arguments object.
1264 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001265 Handle<Object> result = SetElement(arguments, index, initial_value,
1266 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001267 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268 }
1269 } else {
1270 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001271 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001272 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001273 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001274 SetProperty(context_ext, name, initial_value,
1275 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001276 }
1277 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001279 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001280 // The property is not in the function context. It needs to be
1281 // "declared" in the function context's extension context, or in the
1282 // global context.
1283 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001284 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001285 // The function context's extension context exists - use it.
1286 context_ext = Handle<JSObject>(context->extension());
1287 } else {
1288 // The function context's extension context does not exists - allocate
1289 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001290 context_ext = isolate->factory()->NewJSObject(
1291 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001292 // And store it in the extension slot.
1293 context->set_extension(*context_ext);
1294 }
1295 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296
ager@chromium.org7c537e22008-10-16 08:43:32 +00001297 // Declare the property by setting it to the initial value if provided,
1298 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1299 // constant declarations).
1300 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001301 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001302 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001303 // Declaring a const context slot is a conflicting declaration if
1304 // there is a callback with that name in a prototype. It is
1305 // allowed to introduce const variables in
1306 // JSContextExtensionObjects. They are treated specially in
1307 // SetProperty and no setters are invoked for those since they are
1308 // not real JSObjects.
1309 if (initial_value->IsTheHole() &&
1310 !context_ext->IsJSContextExtensionObject()) {
1311 LookupResult lookup;
1312 context_ext->Lookup(*name, &lookup);
1313 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001314 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001315 }
1316 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001317 RETURN_IF_EMPTY_HANDLE(isolate,
1318 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001319 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001320 }
1321
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001322 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001323}
1324
1325
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001326RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001328 // args[0] == name
1329 // args[1] == strict_mode
1330 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331
1332 // Determine if we need to assign to the variable if it already
1333 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001334 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1335 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001336
1337 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001338 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001339 RUNTIME_ASSERT(args[1]->IsSmi());
1340 StrictModeFlag strict_mode =
1341 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1342 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001343
1344 // According to ECMA-262, section 12.2, page 62, the property must
1345 // not be deletable.
1346 PropertyAttributes attributes = DONT_DELETE;
1347
1348 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001349 // there, there is a property with this name in the prototype chain.
1350 // We follow Safari and Firefox behavior and only set the property
1351 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001352 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001353 // Note that objects can have hidden prototypes, so we need to traverse
1354 // the whole chain of hidden prototypes to do a 'local' lookup.
1355 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001357 while (true) {
1358 real_holder->LocalLookup(*name, &lookup);
1359 if (lookup.IsProperty()) {
1360 // Determine if this is a redeclaration of something read-only.
1361 if (lookup.IsReadOnly()) {
1362 // If we found readonly property on one of hidden prototypes,
1363 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001364 if (real_holder != isolate->context()->global()) break;
1365 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001366 }
1367
1368 // Determine if this is a redeclaration of an intercepted read-only
1369 // property and figure out if the property exists at all.
1370 bool found = true;
1371 PropertyType type = lookup.type();
1372 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001373 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001374 Handle<JSObject> holder(real_holder);
1375 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1376 real_holder = *holder;
1377 if (intercepted == ABSENT) {
1378 // The interceptor claims the property isn't there. We need to
1379 // make sure to introduce it.
1380 found = false;
1381 } else if ((intercepted & READ_ONLY) != 0) {
1382 // The property is present, but read-only. Since we're trying to
1383 // overwrite it with a variable declaration we must throw a
1384 // re-declaration error. However if we found readonly property
1385 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001386 if (real_holder != isolate->context()->global()) break;
1387 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001388 }
1389 }
1390
1391 if (found && !assign) {
1392 // The global property is there and we're not assigning any value
1393 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001394 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001395 }
1396
1397 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001398 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001399 return real_holder->SetProperty(
1400 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001401 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001402
1403 Object* proto = real_holder->GetPrototype();
1404 if (!proto->IsJSObject())
1405 break;
1406
1407 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1408 break;
1409
1410 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411 }
1412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001413 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001414 if (assign) {
1415 return global->SetProperty(*name, args[2], attributes, strict_mode);
1416 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001417 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001418}
1419
1420
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001421RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422 // All constants are declared with an initial value. The name
1423 // of the constant is the first argument and the initial value
1424 // is the second.
1425 RUNTIME_ASSERT(args.length() == 2);
1426 CONVERT_ARG_CHECKED(String, name, 0);
1427 Handle<Object> value = args.at<Object>(1);
1428
1429 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001430 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001431
1432 // According to ECMA-262, section 12.2, page 62, the property must
1433 // not be deletable. Since it's a const, it must be READ_ONLY too.
1434 PropertyAttributes attributes =
1435 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1436
1437 // Lookup the property locally in the global object. If it isn't
1438 // there, we add the property and take special precautions to always
1439 // add it as a local property even in case of callbacks in the
1440 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001441 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001442 LookupResult lookup;
1443 global->LocalLookup(*name, &lookup);
1444 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001445 return global->SetLocalPropertyIgnoreAttributes(*name,
1446 *value,
1447 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001448 }
1449
1450 // Determine if this is a redeclaration of something not
1451 // read-only. In case the result is hidden behind an interceptor we
1452 // need to ask it for the property attributes.
1453 if (!lookup.IsReadOnly()) {
1454 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001455 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001456 }
1457
1458 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1459
1460 // Throw re-declaration error if the intercepted property is present
1461 // but not read-only.
1462 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001463 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001464 }
1465
1466 // Restore global object from context (in case of GC) and continue
1467 // with setting the value because the property is either absent or
1468 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001469 HandleScope handle_scope(isolate);
1470 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001472 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473 // property through an interceptor and only do it if it's
1474 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001475 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001476 RETURN_IF_EMPTY_HANDLE(isolate,
1477 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001478 name,
1479 value,
1480 attributes,
1481 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001482 return *value;
1483 }
1484
1485 // Set the value, but only we're assigning the initial value to a
1486 // constant. For now, we determine this by checking if the
1487 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001488 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489 PropertyType type = lookup.type();
1490 if (type == FIELD) {
1491 FixedArray* properties = global->properties();
1492 int index = lookup.GetFieldIndex();
1493 if (properties->get(index)->IsTheHole()) {
1494 properties->set(index, *value);
1495 }
1496 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001497 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1498 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001499 }
1500 } else {
1501 // Ignore re-initialization of constants that have already been
1502 // assigned a function value.
1503 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1504 }
1505
1506 // Use the set value as the result of the operation.
1507 return *value;
1508}
1509
1510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001511RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001512 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001513 ASSERT(args.length() == 3);
1514
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001515 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001516 ASSERT(!value->IsTheHole());
1517 CONVERT_ARG_CHECKED(Context, context, 1);
1518 Handle<String> name(String::cast(args[2]));
1519
1520 // Initializations are always done in the function context.
1521 context = Handle<Context>(context->fcontext());
1522
1523 int index;
1524 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001525 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001526 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001527 context->Lookup(name, flags, &index, &attributes);
1528
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001529 // In most situations, the property introduced by the const
1530 // declaration should be present in the context extension object.
1531 // However, because declaration and initialization are separate, the
1532 // property might have been deleted (if it was introduced by eval)
1533 // before we reach the initialization point.
1534 //
1535 // Example:
1536 //
1537 // function f() { eval("delete x; const x;"); }
1538 //
1539 // In that case, the initialization behaves like a normal assignment
1540 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001541 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001542 // Property was found in a context.
1543 if (holder->IsContext()) {
1544 // The holder cannot be the function context. If it is, there
1545 // should have been a const redeclaration error when declaring
1546 // the const property.
1547 ASSERT(!holder.is_identical_to(context));
1548 if ((attributes & READ_ONLY) == 0) {
1549 Handle<Context>::cast(holder)->set(index, *value);
1550 }
1551 } else {
1552 // The holder is an arguments object.
1553 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001554 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001555 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001556 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001557 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001558 }
1559 return *value;
1560 }
1561
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001562 // The property could not be found, we introduce it in the global
1563 // context.
1564 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001565 Handle<JSObject> global = Handle<JSObject>(
1566 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001567 // Strict mode not needed (const disallowed in strict mode).
1568 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001569 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001570 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001571 return *value;
1572 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001573
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001574 // The property was present in a context extension object.
1575 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001577 if (*context_ext == context->extension()) {
1578 // This is the property that was introduced by the const
1579 // declaration. Set it if it hasn't been set before. NOTE: We
1580 // cannot use GetProperty() to get the current value as it
1581 // 'unholes' the value.
1582 LookupResult lookup;
1583 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1584 ASSERT(lookup.IsProperty()); // the property was declared
1585 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1586
1587 PropertyType type = lookup.type();
1588 if (type == FIELD) {
1589 FixedArray* properties = context_ext->properties();
1590 int index = lookup.GetFieldIndex();
1591 if (properties->get(index)->IsTheHole()) {
1592 properties->set(index, *value);
1593 }
1594 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001595 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1596 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001597 }
1598 } else {
1599 // We should not reach here. Any real, named property should be
1600 // either a field or a dictionary slot.
1601 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 }
1603 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001604 // The property was found in a different context extension object.
1605 // Set it if it is not a read-only property.
1606 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001607 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001608 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001609 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001610 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001611 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001613
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001614 return *value;
1615}
1616
1617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001618RUNTIME_FUNCTION(MaybeObject*,
1619 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001620 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001621 ASSERT(args.length() == 2);
1622 CONVERT_ARG_CHECKED(JSObject, object, 0);
1623 CONVERT_SMI_CHECKED(properties, args[1]);
1624 if (object->HasFastProperties()) {
1625 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1626 }
1627 return *object;
1628}
1629
1630
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001631RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001632 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001633 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001634 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1635 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001636 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001637 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001638 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001639 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001640 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001641 RUNTIME_ASSERT(index >= 0);
1642 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001643 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001644 Handle<Object> result = RegExpImpl::Exec(regexp,
1645 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001646 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001647 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001648 if (result.is_null()) return Failure::Exception();
1649 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001650}
1651
1652
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001653RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001654 ASSERT(args.length() == 3);
1655 CONVERT_SMI_CHECKED(elements_count, args[0]);
1656 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001657 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001658 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001659 Object* new_object;
1660 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001661 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001662 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1663 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001664 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001665 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1666 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001667 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1668 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001669 {
1670 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001671 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001672 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001673 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001674 }
1675 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001676 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001677 array->set_elements(elements);
1678 array->set_length(Smi::FromInt(elements_count));
1679 // Write in-object properties after the length of the array.
1680 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1681 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1682 return array;
1683}
1684
1685
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001686RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001687 AssertNoAllocation no_alloc;
1688 ASSERT(args.length() == 5);
1689 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1690 CONVERT_CHECKED(String, source, args[1]);
1691
1692 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001693 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001694
1695 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001696 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001697
1698 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001699 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001700
1701 Map* map = regexp->map();
1702 Object* constructor = map->constructor();
1703 if (constructor->IsJSFunction() &&
1704 JSFunction::cast(constructor)->initial_map() == map) {
1705 // If we still have the original map, set in-object properties directly.
1706 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1707 // TODO(lrn): Consider skipping write barrier on booleans as well.
1708 // Both true and false should be in oldspace at all times.
1709 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1710 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1711 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1712 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1713 Smi::FromInt(0),
1714 SKIP_WRITE_BARRIER);
1715 return regexp;
1716 }
1717
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001718 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001719 PropertyAttributes final =
1720 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1721 PropertyAttributes writable =
1722 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001723 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001724 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001725 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001726 source,
1727 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001728 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001729 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001730 global,
1731 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001732 ASSERT(!result->IsFailure());
1733 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001734 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001735 ignoreCase,
1736 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001737 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001738 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001739 multiline,
1740 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001741 ASSERT(!result->IsFailure());
1742 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001743 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001744 Smi::FromInt(0),
1745 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001746 ASSERT(!result->IsFailure());
1747 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001748 return regexp;
1749}
1750
1751
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001752RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001753 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001754 ASSERT(args.length() == 1);
1755 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1756 // This is necessary to enable fast checks for absence of elements
1757 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001758 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001759 return Smi::FromInt(0);
1760}
1761
1762
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1764 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001765 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001766 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001767 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1768 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1769 Handle<JSFunction> optimized =
1770 isolate->factory()->NewFunction(key,
1771 JS_OBJECT_TYPE,
1772 JSObject::kHeaderSize,
1773 code,
1774 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001775 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001776 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001777 return optimized;
1778}
1779
1780
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001781RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001782 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001783 ASSERT(args.length() == 1);
1784 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1785
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001786 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1787 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1788 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1789 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1790 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1791 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1792 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001793
1794 return *holder;
1795}
1796
1797
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001798RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001799 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001800 Context* global_context =
1801 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001802 return global_context->global()->global_receiver();
1803}
1804
1805
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001806RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001807 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001808 ASSERT(args.length() == 4);
1809 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1810 int index = Smi::cast(args[1])->value();
1811 Handle<String> pattern = args.at<String>(2);
1812 Handle<String> flags = args.at<String>(3);
1813
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001814 // Get the RegExp function from the context in the literals array.
1815 // This is the RegExp function from the context in which the
1816 // function was created. We do not use the RegExp function from the
1817 // current global context because this might be the RegExp function
1818 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001819 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001820 Handle<JSFunction>(
1821 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001822 // Compute the regular expression literal.
1823 bool has_pending_exception;
1824 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001825 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1826 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001827 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001828 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001829 return Failure::Exception();
1830 }
1831 literals->set(index, *regexp);
1832 return *regexp;
1833}
1834
1835
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001836RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001837 NoHandleAllocation ha;
1838 ASSERT(args.length() == 1);
1839
1840 CONVERT_CHECKED(JSFunction, f, args[0]);
1841 return f->shared()->name();
1842}
1843
1844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001845RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001846 NoHandleAllocation ha;
1847 ASSERT(args.length() == 2);
1848
1849 CONVERT_CHECKED(JSFunction, f, args[0]);
1850 CONVERT_CHECKED(String, name, args[1]);
1851 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001852 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001853}
1854
1855
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001856RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001857 NoHandleAllocation ha;
1858 ASSERT(args.length() == 1);
1859
1860 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861 Object* obj = f->RemovePrototype();
1862 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001863
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001864 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001865}
1866
1867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001868RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001869 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001870 ASSERT(args.length() == 1);
1871
1872 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001873 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1874 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001875
1876 return *GetScriptWrapper(Handle<Script>::cast(script));
1877}
1878
1879
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001880RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001881 NoHandleAllocation ha;
1882 ASSERT(args.length() == 1);
1883
1884 CONVERT_CHECKED(JSFunction, f, args[0]);
1885 return f->shared()->GetSourceCode();
1886}
1887
1888
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001889RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890 NoHandleAllocation ha;
1891 ASSERT(args.length() == 1);
1892
1893 CONVERT_CHECKED(JSFunction, fun, args[0]);
1894 int pos = fun->shared()->start_position();
1895 return Smi::FromInt(pos);
1896}
1897
1898
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001899RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001900 ASSERT(args.length() == 2);
1901
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001902 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001903 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1904
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001905 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1906
1907 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001908 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001909}
1910
1911
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001912RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001913 NoHandleAllocation ha;
1914 ASSERT(args.length() == 2);
1915
1916 CONVERT_CHECKED(JSFunction, fun, args[0]);
1917 CONVERT_CHECKED(String, name, args[1]);
1918 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001919 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001920}
1921
1922
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001923RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001924 NoHandleAllocation ha;
1925 ASSERT(args.length() == 2);
1926
1927 CONVERT_CHECKED(JSFunction, fun, args[0]);
1928 CONVERT_CHECKED(Smi, length, args[1]);
1929 fun->shared()->set_length(length->value());
1930 return length;
1931}
1932
1933
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001934RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001935 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001936 ASSERT(args.length() == 2);
1937
1938 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001939 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001940 Object* obj;
1941 { MaybeObject* maybe_obj =
1942 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1943 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1944 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001945 return args[0]; // return TOS
1946}
1947
1948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001949RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001950 NoHandleAllocation ha;
1951 ASSERT(args.length() == 1);
1952
1953 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001954 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1955 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001956}
1957
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001958
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001959RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001960 NoHandleAllocation ha;
1961 ASSERT(args.length() == 1);
1962
1963 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001964 return f->IsBuiltin() ? isolate->heap()->true_value() :
1965 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001966}
1967
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001968
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001969RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001970 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001971 ASSERT(args.length() == 2);
1972
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001973 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001974 Handle<Object> code = args.at<Object>(1);
1975
1976 Handle<Context> context(target->context());
1977
1978 if (!code->IsNull()) {
1979 RUNTIME_ASSERT(code->IsJSFunction());
1980 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001981 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001982
1983 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001984 return Failure::Exception();
1985 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001986 // Since we don't store the source for this we should never
1987 // optimize this.
1988 shared->code()->set_optimizable(false);
1989
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001990 // Set the code, scope info, formal parameter count,
1991 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001992 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001993 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001994 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001995 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001996 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001997 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001998 // Set the source code of the target function to undefined.
1999 // SetCode is only used for built-in constructors like String,
2000 // Array, and Object, and some web code
2001 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002002 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002003 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002004 // Clear the optimization hints related to the compiled code as these are no
2005 // longer valid when the code is overwritten.
2006 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002007 context = Handle<Context>(fun->context());
2008
2009 // Make sure we get a fresh copy of the literal vector to avoid
2010 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002011 int number_of_literals = fun->NumberOfLiterals();
2012 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002013 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002014 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002015 // Insert the object, regexp and array functions in the literals
2016 // array prefix. These are the functions that will be used when
2017 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002018 literals->set(JSFunction::kLiteralGlobalContextIndex,
2019 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002020 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002021 // It's okay to skip the write barrier here because the literals
2022 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002023 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002024 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002025 }
2026
2027 target->set_context(*context);
2028 return *target;
2029}
2030
2031
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002032RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002033 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002034 ASSERT(args.length() == 2);
2035 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2036 CONVERT_SMI_CHECKED(num, args[1]);
2037 RUNTIME_ASSERT(num >= 0);
2038 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002039 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002040}
2041
2042
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002043MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2044 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002045 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002046 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002047 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002048 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002049 }
2050 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002051 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002052}
2053
2054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002055RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002056 NoHandleAllocation ha;
2057 ASSERT(args.length() == 2);
2058
2059 CONVERT_CHECKED(String, subject, args[0]);
2060 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002061 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002062
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002063 uint32_t i = 0;
2064 if (index->IsSmi()) {
2065 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002066 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002067 i = value;
2068 } else {
2069 ASSERT(index->IsHeapNumber());
2070 double value = HeapNumber::cast(index)->value();
2071 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002072 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002073
2074 // Flatten the string. If someone wants to get a char at an index
2075 // in a cons string, it is likely that more indices will be
2076 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002077 Object* flat;
2078 { MaybeObject* maybe_flat = subject->TryFlatten();
2079 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2080 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002081 subject = String::cast(flat);
2082
2083 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002084 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002085 }
2086
2087 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002088}
2089
2090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002091RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002092 NoHandleAllocation ha;
2093 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002094 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002095}
2096
lrn@chromium.org25156de2010-04-06 13:10:27 +00002097
2098class FixedArrayBuilder {
2099 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002100 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2101 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002102 length_(0) {
2103 // Require a non-zero initial size. Ensures that doubling the size to
2104 // extend the array will work.
2105 ASSERT(initial_capacity > 0);
2106 }
2107
2108 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2109 : array_(backing_store),
2110 length_(0) {
2111 // Require a non-zero initial size. Ensures that doubling the size to
2112 // extend the array will work.
2113 ASSERT(backing_store->length() > 0);
2114 }
2115
2116 bool HasCapacity(int elements) {
2117 int length = array_->length();
2118 int required_length = length_ + elements;
2119 return (length >= required_length);
2120 }
2121
2122 void EnsureCapacity(int elements) {
2123 int length = array_->length();
2124 int required_length = length_ + elements;
2125 if (length < required_length) {
2126 int new_length = length;
2127 do {
2128 new_length *= 2;
2129 } while (new_length < required_length);
2130 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002131 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002132 array_->CopyTo(0, *extended_array, 0, length_);
2133 array_ = extended_array;
2134 }
2135 }
2136
2137 void Add(Object* value) {
2138 ASSERT(length_ < capacity());
2139 array_->set(length_, value);
2140 length_++;
2141 }
2142
2143 void Add(Smi* value) {
2144 ASSERT(length_ < capacity());
2145 array_->set(length_, value);
2146 length_++;
2147 }
2148
2149 Handle<FixedArray> array() {
2150 return array_;
2151 }
2152
2153 int length() {
2154 return length_;
2155 }
2156
2157 int capacity() {
2158 return array_->length();
2159 }
2160
2161 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002162 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002163 result_array->set_length(Smi::FromInt(length_));
2164 return result_array;
2165 }
2166
2167 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2168 target_array->set_elements(*array_);
2169 target_array->set_length(Smi::FromInt(length_));
2170 return target_array;
2171 }
2172
2173 private:
2174 Handle<FixedArray> array_;
2175 int length_;
2176};
2177
2178
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002179// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002180const int kStringBuilderConcatHelperLengthBits = 11;
2181const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002182
2183template <typename schar>
2184static inline void StringBuilderConcatHelper(String*,
2185 schar*,
2186 FixedArray*,
2187 int);
2188
lrn@chromium.org25156de2010-04-06 13:10:27 +00002189typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2190 StringBuilderSubstringLength;
2191typedef BitField<int,
2192 kStringBuilderConcatHelperLengthBits,
2193 kStringBuilderConcatHelperPositionBits>
2194 StringBuilderSubstringPosition;
2195
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002196
2197class ReplacementStringBuilder {
2198 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002199 ReplacementStringBuilder(Heap* heap,
2200 Handle<String> subject,
2201 int estimated_part_count)
2202 : heap_(heap),
2203 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002204 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002205 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002206 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002207 // Require a non-zero initial size. Ensures that doubling the size to
2208 // extend the array will work.
2209 ASSERT(estimated_part_count > 0);
2210 }
2211
lrn@chromium.org25156de2010-04-06 13:10:27 +00002212 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2213 int from,
2214 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002215 ASSERT(from >= 0);
2216 int length = to - from;
2217 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002218 if (StringBuilderSubstringLength::is_valid(length) &&
2219 StringBuilderSubstringPosition::is_valid(from)) {
2220 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2221 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002222 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002223 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002224 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002225 builder->Add(Smi::FromInt(-length));
2226 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002227 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002228 }
2229
2230
2231 void EnsureCapacity(int elements) {
2232 array_builder_.EnsureCapacity(elements);
2233 }
2234
2235
2236 void AddSubjectSlice(int from, int to) {
2237 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002238 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002239 }
2240
2241
2242 void AddString(Handle<String> string) {
2243 int length = string->length();
2244 ASSERT(length > 0);
2245 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002246 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002247 is_ascii_ = false;
2248 }
2249 IncrementCharacterCount(length);
2250 }
2251
2252
2253 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002254 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002255 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002256 }
2257
2258 Handle<String> joined_string;
2259 if (is_ascii_) {
2260 joined_string = NewRawAsciiString(character_count_);
2261 AssertNoAllocation no_alloc;
2262 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2263 char* char_buffer = seq->GetChars();
2264 StringBuilderConcatHelper(*subject_,
2265 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002266 *array_builder_.array(),
2267 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002268 } else {
2269 // Non-ASCII.
2270 joined_string = NewRawTwoByteString(character_count_);
2271 AssertNoAllocation no_alloc;
2272 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2273 uc16* char_buffer = seq->GetChars();
2274 StringBuilderConcatHelper(*subject_,
2275 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002276 *array_builder_.array(),
2277 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002278 }
2279 return joined_string;
2280 }
2281
2282
2283 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002284 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002285 V8::FatalProcessOutOfMemory("String.replace result too large.");
2286 }
2287 character_count_ += by;
2288 }
2289
lrn@chromium.org25156de2010-04-06 13:10:27 +00002290 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002291 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002292 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002293
lrn@chromium.org25156de2010-04-06 13:10:27 +00002294 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002295 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002296 CALL_HEAP_FUNCTION(heap_->isolate(),
2297 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002298 }
2299
2300
2301 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002302 CALL_HEAP_FUNCTION(heap_->isolate(),
2303 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002304 }
2305
2306
2307 void AddElement(Object* element) {
2308 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002309 ASSERT(array_builder_.capacity() > array_builder_.length());
2310 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002311 }
2312
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002313 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002314 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002315 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002316 int character_count_;
2317 bool is_ascii_;
2318};
2319
2320
2321class CompiledReplacement {
2322 public:
2323 CompiledReplacement()
2324 : parts_(1), replacement_substrings_(0) {}
2325
2326 void Compile(Handle<String> replacement,
2327 int capture_count,
2328 int subject_length);
2329
2330 void Apply(ReplacementStringBuilder* builder,
2331 int match_from,
2332 int match_to,
2333 Handle<JSArray> last_match_info);
2334
2335 // Number of distinct parts of the replacement pattern.
2336 int parts() {
2337 return parts_.length();
2338 }
2339 private:
2340 enum PartType {
2341 SUBJECT_PREFIX = 1,
2342 SUBJECT_SUFFIX,
2343 SUBJECT_CAPTURE,
2344 REPLACEMENT_SUBSTRING,
2345 REPLACEMENT_STRING,
2346
2347 NUMBER_OF_PART_TYPES
2348 };
2349
2350 struct ReplacementPart {
2351 static inline ReplacementPart SubjectMatch() {
2352 return ReplacementPart(SUBJECT_CAPTURE, 0);
2353 }
2354 static inline ReplacementPart SubjectCapture(int capture_index) {
2355 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2356 }
2357 static inline ReplacementPart SubjectPrefix() {
2358 return ReplacementPart(SUBJECT_PREFIX, 0);
2359 }
2360 static inline ReplacementPart SubjectSuffix(int subject_length) {
2361 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2362 }
2363 static inline ReplacementPart ReplacementString() {
2364 return ReplacementPart(REPLACEMENT_STRING, 0);
2365 }
2366 static inline ReplacementPart ReplacementSubString(int from, int to) {
2367 ASSERT(from >= 0);
2368 ASSERT(to > from);
2369 return ReplacementPart(-from, to);
2370 }
2371
2372 // If tag <= 0 then it is the negation of a start index of a substring of
2373 // the replacement pattern, otherwise it's a value from PartType.
2374 ReplacementPart(int tag, int data)
2375 : tag(tag), data(data) {
2376 // Must be non-positive or a PartType value.
2377 ASSERT(tag < NUMBER_OF_PART_TYPES);
2378 }
2379 // Either a value of PartType or a non-positive number that is
2380 // the negation of an index into the replacement string.
2381 int tag;
2382 // The data value's interpretation depends on the value of tag:
2383 // tag == SUBJECT_PREFIX ||
2384 // tag == SUBJECT_SUFFIX: data is unused.
2385 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2386 // tag == REPLACEMENT_SUBSTRING ||
2387 // tag == REPLACEMENT_STRING: data is index into array of substrings
2388 // of the replacement string.
2389 // tag <= 0: Temporary representation of the substring of the replacement
2390 // string ranging over -tag .. data.
2391 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2392 // substring objects.
2393 int data;
2394 };
2395
2396 template<typename Char>
2397 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2398 Vector<Char> characters,
2399 int capture_count,
2400 int subject_length) {
2401 int length = characters.length();
2402 int last = 0;
2403 for (int i = 0; i < length; i++) {
2404 Char c = characters[i];
2405 if (c == '$') {
2406 int next_index = i + 1;
2407 if (next_index == length) { // No next character!
2408 break;
2409 }
2410 Char c2 = characters[next_index];
2411 switch (c2) {
2412 case '$':
2413 if (i > last) {
2414 // There is a substring before. Include the first "$".
2415 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2416 last = next_index + 1; // Continue after the second "$".
2417 } else {
2418 // Let the next substring start with the second "$".
2419 last = next_index;
2420 }
2421 i = next_index;
2422 break;
2423 case '`':
2424 if (i > last) {
2425 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2426 }
2427 parts->Add(ReplacementPart::SubjectPrefix());
2428 i = next_index;
2429 last = i + 1;
2430 break;
2431 case '\'':
2432 if (i > last) {
2433 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2434 }
2435 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2436 i = next_index;
2437 last = i + 1;
2438 break;
2439 case '&':
2440 if (i > last) {
2441 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2442 }
2443 parts->Add(ReplacementPart::SubjectMatch());
2444 i = next_index;
2445 last = i + 1;
2446 break;
2447 case '0':
2448 case '1':
2449 case '2':
2450 case '3':
2451 case '4':
2452 case '5':
2453 case '6':
2454 case '7':
2455 case '8':
2456 case '9': {
2457 int capture_ref = c2 - '0';
2458 if (capture_ref > capture_count) {
2459 i = next_index;
2460 continue;
2461 }
2462 int second_digit_index = next_index + 1;
2463 if (second_digit_index < length) {
2464 // Peek ahead to see if we have two digits.
2465 Char c3 = characters[second_digit_index];
2466 if ('0' <= c3 && c3 <= '9') { // Double digits.
2467 int double_digit_ref = capture_ref * 10 + c3 - '0';
2468 if (double_digit_ref <= capture_count) {
2469 next_index = second_digit_index;
2470 capture_ref = double_digit_ref;
2471 }
2472 }
2473 }
2474 if (capture_ref > 0) {
2475 if (i > last) {
2476 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2477 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002478 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002479 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2480 last = next_index + 1;
2481 }
2482 i = next_index;
2483 break;
2484 }
2485 default:
2486 i = next_index;
2487 break;
2488 }
2489 }
2490 }
2491 if (length > last) {
2492 if (last == 0) {
2493 parts->Add(ReplacementPart::ReplacementString());
2494 } else {
2495 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2496 }
2497 }
2498 }
2499
2500 ZoneList<ReplacementPart> parts_;
2501 ZoneList<Handle<String> > replacement_substrings_;
2502};
2503
2504
2505void CompiledReplacement::Compile(Handle<String> replacement,
2506 int capture_count,
2507 int subject_length) {
2508 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002509 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002510 AssertNoAllocation no_alloc;
2511 ParseReplacementPattern(&parts_,
2512 replacement->ToAsciiVector(),
2513 capture_count,
2514 subject_length);
2515 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002516 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002517 AssertNoAllocation no_alloc;
2518
2519 ParseReplacementPattern(&parts_,
2520 replacement->ToUC16Vector(),
2521 capture_count,
2522 subject_length);
2523 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002524 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002525 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002526 int substring_index = 0;
2527 for (int i = 0, n = parts_.length(); i < n; i++) {
2528 int tag = parts_[i].tag;
2529 if (tag <= 0) { // A replacement string slice.
2530 int from = -tag;
2531 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002532 replacement_substrings_.Add(
2533 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002534 parts_[i].tag = REPLACEMENT_SUBSTRING;
2535 parts_[i].data = substring_index;
2536 substring_index++;
2537 } else if (tag == REPLACEMENT_STRING) {
2538 replacement_substrings_.Add(replacement);
2539 parts_[i].data = substring_index;
2540 substring_index++;
2541 }
2542 }
2543}
2544
2545
2546void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2547 int match_from,
2548 int match_to,
2549 Handle<JSArray> last_match_info) {
2550 for (int i = 0, n = parts_.length(); i < n; i++) {
2551 ReplacementPart part = parts_[i];
2552 switch (part.tag) {
2553 case SUBJECT_PREFIX:
2554 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2555 break;
2556 case SUBJECT_SUFFIX: {
2557 int subject_length = part.data;
2558 if (match_to < subject_length) {
2559 builder->AddSubjectSlice(match_to, subject_length);
2560 }
2561 break;
2562 }
2563 case SUBJECT_CAPTURE: {
2564 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002565 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002566 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2567 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2568 if (from >= 0 && to > from) {
2569 builder->AddSubjectSlice(from, to);
2570 }
2571 break;
2572 }
2573 case REPLACEMENT_SUBSTRING:
2574 case REPLACEMENT_STRING:
2575 builder->AddString(replacement_substrings_[part.data]);
2576 break;
2577 default:
2578 UNREACHABLE();
2579 }
2580 }
2581}
2582
2583
2584
lrn@chromium.org303ada72010-10-27 09:33:13 +00002585MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002586 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002587 String* subject,
2588 JSRegExp* regexp,
2589 String* replacement,
2590 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002591 ASSERT(subject->IsFlat());
2592 ASSERT(replacement->IsFlat());
2593
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002594 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002595
2596 int length = subject->length();
2597 Handle<String> subject_handle(subject);
2598 Handle<JSRegExp> regexp_handle(regexp);
2599 Handle<String> replacement_handle(replacement);
2600 Handle<JSArray> last_match_info_handle(last_match_info);
2601 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2602 subject_handle,
2603 0,
2604 last_match_info_handle);
2605 if (match.is_null()) {
2606 return Failure::Exception();
2607 }
2608 if (match->IsNull()) {
2609 return *subject_handle;
2610 }
2611
2612 int capture_count = regexp_handle->CaptureCount();
2613
2614 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002615 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002616 CompiledReplacement compiled_replacement;
2617 compiled_replacement.Compile(replacement_handle,
2618 capture_count,
2619 length);
2620
2621 bool is_global = regexp_handle->GetFlags().is_global();
2622
2623 // Guessing the number of parts that the final result string is built
2624 // from. Global regexps can match any number of times, so we guess
2625 // conservatively.
2626 int expected_parts =
2627 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002628 ReplacementStringBuilder builder(isolate->heap(),
2629 subject_handle,
2630 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002631
2632 // Index of end of last match.
2633 int prev = 0;
2634
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002635 // Number of parts added by compiled replacement plus preceeding
2636 // string and possibly suffix after last match. It is possible for
2637 // all components to use two elements when encoded as two smis.
2638 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002639 bool matched = true;
2640 do {
2641 ASSERT(last_match_info_handle->HasFastElements());
2642 // Increase the capacity of the builder before entering local handle-scope,
2643 // so its internal buffer can safely allocate a new handle if it grows.
2644 builder.EnsureCapacity(parts_added_per_loop);
2645
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002646 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002647 int start, end;
2648 {
2649 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002650 FixedArray* match_info_array =
2651 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002652
2653 ASSERT_EQ(capture_count * 2 + 2,
2654 RegExpImpl::GetLastCaptureCount(match_info_array));
2655 start = RegExpImpl::GetCapture(match_info_array, 0);
2656 end = RegExpImpl::GetCapture(match_info_array, 1);
2657 }
2658
2659 if (prev < start) {
2660 builder.AddSubjectSlice(prev, start);
2661 }
2662 compiled_replacement.Apply(&builder,
2663 start,
2664 end,
2665 last_match_info_handle);
2666 prev = end;
2667
2668 // Only continue checking for global regexps.
2669 if (!is_global) break;
2670
2671 // Continue from where the match ended, unless it was an empty match.
2672 int next = end;
2673 if (start == end) {
2674 next = end + 1;
2675 if (next > length) break;
2676 }
2677
2678 match = RegExpImpl::Exec(regexp_handle,
2679 subject_handle,
2680 next,
2681 last_match_info_handle);
2682 if (match.is_null()) {
2683 return Failure::Exception();
2684 }
2685 matched = !match->IsNull();
2686 } while (matched);
2687
2688 if (prev < length) {
2689 builder.AddSubjectSlice(prev, length);
2690 }
2691
2692 return *(builder.ToString());
2693}
2694
2695
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002696template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002697MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002698 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002699 String* subject,
2700 JSRegExp* regexp,
2701 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002702 ASSERT(subject->IsFlat());
2703
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002704 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002705
2706 Handle<String> subject_handle(subject);
2707 Handle<JSRegExp> regexp_handle(regexp);
2708 Handle<JSArray> last_match_info_handle(last_match_info);
2709 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2710 subject_handle,
2711 0,
2712 last_match_info_handle);
2713 if (match.is_null()) return Failure::Exception();
2714 if (match->IsNull()) return *subject_handle;
2715
2716 ASSERT(last_match_info_handle->HasFastElements());
2717
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002718 int start, end;
2719 {
2720 AssertNoAllocation match_info_array_is_not_in_a_handle;
2721 FixedArray* match_info_array =
2722 FixedArray::cast(last_match_info_handle->elements());
2723
2724 start = RegExpImpl::GetCapture(match_info_array, 0);
2725 end = RegExpImpl::GetCapture(match_info_array, 1);
2726 }
2727
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002728 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002729 int new_length = length - (end - start);
2730 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002731 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002732 }
2733 Handle<ResultSeqString> answer;
2734 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002735 answer = Handle<ResultSeqString>::cast(
2736 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002737 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002738 answer = Handle<ResultSeqString>::cast(
2739 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002740 }
2741
2742 // If the regexp isn't global, only match once.
2743 if (!regexp_handle->GetFlags().is_global()) {
2744 if (start > 0) {
2745 String::WriteToFlat(*subject_handle,
2746 answer->GetChars(),
2747 0,
2748 start);
2749 }
2750 if (end < length) {
2751 String::WriteToFlat(*subject_handle,
2752 answer->GetChars() + start,
2753 end,
2754 length);
2755 }
2756 return *answer;
2757 }
2758
2759 int prev = 0; // Index of end of last match.
2760 int next = 0; // Start of next search (prev unless last match was empty).
2761 int position = 0;
2762
2763 do {
2764 if (prev < start) {
2765 // Add substring subject[prev;start] to answer string.
2766 String::WriteToFlat(*subject_handle,
2767 answer->GetChars() + position,
2768 prev,
2769 start);
2770 position += start - prev;
2771 }
2772 prev = end;
2773 next = end;
2774 // Continue from where the match ended, unless it was an empty match.
2775 if (start == end) {
2776 next++;
2777 if (next > length) break;
2778 }
2779 match = RegExpImpl::Exec(regexp_handle,
2780 subject_handle,
2781 next,
2782 last_match_info_handle);
2783 if (match.is_null()) return Failure::Exception();
2784 if (match->IsNull()) break;
2785
2786 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002787 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002788 {
2789 AssertNoAllocation match_info_array_is_not_in_a_handle;
2790 FixedArray* match_info_array =
2791 FixedArray::cast(last_match_info_handle->elements());
2792 start = RegExpImpl::GetCapture(match_info_array, 0);
2793 end = RegExpImpl::GetCapture(match_info_array, 1);
2794 }
2795 } while (true);
2796
2797 if (prev < length) {
2798 // Add substring subject[prev;length] to answer string.
2799 String::WriteToFlat(*subject_handle,
2800 answer->GetChars() + position,
2801 prev,
2802 length);
2803 position += length - prev;
2804 }
2805
2806 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002807 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002808 }
2809
2810 // Shorten string and fill
2811 int string_size = ResultSeqString::SizeFor(position);
2812 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2813 int delta = allocated_string_size - string_size;
2814
2815 answer->set_length(position);
2816 if (delta == 0) return *answer;
2817
2818 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002819 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002820
2821 return *answer;
2822}
2823
2824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002825RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002826 ASSERT(args.length() == 4);
2827
2828 CONVERT_CHECKED(String, subject, args[0]);
2829 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002830 Object* flat_subject;
2831 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2832 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2833 return maybe_flat_subject;
2834 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002835 }
2836 subject = String::cast(flat_subject);
2837 }
2838
2839 CONVERT_CHECKED(String, replacement, args[2]);
2840 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002841 Object* flat_replacement;
2842 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2843 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2844 return maybe_flat_replacement;
2845 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002846 }
2847 replacement = String::cast(flat_replacement);
2848 }
2849
2850 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2851 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2852
2853 ASSERT(last_match_info->HasFastElements());
2854
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002855 if (replacement->length() == 0) {
2856 if (subject->HasOnlyAsciiChars()) {
2857 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002858 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002859 } else {
2860 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002861 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002862 }
2863 }
2864
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002865 return StringReplaceRegExpWithString(isolate,
2866 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002867 regexp,
2868 replacement,
2869 last_match_info);
2870}
2871
2872
ager@chromium.org7c537e22008-10-16 08:43:32 +00002873// Perform string match of pattern on subject, starting at start index.
2874// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002875// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002876int Runtime::StringMatch(Isolate* isolate,
2877 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002878 Handle<String> pat,
2879 int start_index) {
2880 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002881 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002882
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002883 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002884 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002885
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002886 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002887 if (start_index + pattern_length > subject_length) return -1;
2888
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002889 if (!sub->IsFlat()) FlattenString(sub);
2890 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002891
ager@chromium.org7c537e22008-10-16 08:43:32 +00002892 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002893 // Extract flattened substrings of cons strings before determining asciiness.
2894 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002895 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002896 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002897 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002898
ager@chromium.org7c537e22008-10-16 08:43:32 +00002899 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002900 if (seq_pat->IsAsciiRepresentation()) {
2901 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2902 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002903 return SearchString(isolate,
2904 seq_sub->ToAsciiVector(),
2905 pat_vector,
2906 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002907 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002908 return SearchString(isolate,
2909 seq_sub->ToUC16Vector(),
2910 pat_vector,
2911 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002912 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002913 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2914 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002915 return SearchString(isolate,
2916 seq_sub->ToAsciiVector(),
2917 pat_vector,
2918 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002919 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002920 return SearchString(isolate,
2921 seq_sub->ToUC16Vector(),
2922 pat_vector,
2923 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002924}
2925
2926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002927RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002928 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002929 ASSERT(args.length() == 3);
2930
ager@chromium.org7c537e22008-10-16 08:43:32 +00002931 CONVERT_ARG_CHECKED(String, sub, 0);
2932 CONVERT_ARG_CHECKED(String, pat, 1);
2933
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002934 Object* index = args[2];
2935 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002936 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002937
ager@chromium.org870a0b62008-11-04 11:43:05 +00002938 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002939 int position =
2940 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002941 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002942}
2943
2944
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002945template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002946static int StringMatchBackwards(Vector<const schar> subject,
2947 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002948 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002949 int pattern_length = pattern.length();
2950 ASSERT(pattern_length >= 1);
2951 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002952
2953 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002954 for (int i = 0; i < pattern_length; i++) {
2955 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002956 if (c > String::kMaxAsciiCharCode) {
2957 return -1;
2958 }
2959 }
2960 }
2961
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002962 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002963 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002964 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002965 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002966 while (j < pattern_length) {
2967 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002968 break;
2969 }
2970 j++;
2971 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002972 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002973 return i;
2974 }
2975 }
2976 return -1;
2977}
2978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002979RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002980 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002981 ASSERT(args.length() == 3);
2982
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002983 CONVERT_ARG_CHECKED(String, sub, 0);
2984 CONVERT_ARG_CHECKED(String, pat, 1);
2985
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002986 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002987 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002988 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002989
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002990 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002991 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002992
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002993 if (start_index + pat_length > sub_length) {
2994 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002995 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002996
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002997 if (pat_length == 0) {
2998 return Smi::FromInt(start_index);
2999 }
3000
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003001 if (!sub->IsFlat()) FlattenString(sub);
3002 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003003
3004 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3005
3006 int position = -1;
3007
3008 if (pat->IsAsciiRepresentation()) {
3009 Vector<const char> pat_vector = pat->ToAsciiVector();
3010 if (sub->IsAsciiRepresentation()) {
3011 position = StringMatchBackwards(sub->ToAsciiVector(),
3012 pat_vector,
3013 start_index);
3014 } else {
3015 position = StringMatchBackwards(sub->ToUC16Vector(),
3016 pat_vector,
3017 start_index);
3018 }
3019 } else {
3020 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3021 if (sub->IsAsciiRepresentation()) {
3022 position = StringMatchBackwards(sub->ToAsciiVector(),
3023 pat_vector,
3024 start_index);
3025 } else {
3026 position = StringMatchBackwards(sub->ToUC16Vector(),
3027 pat_vector,
3028 start_index);
3029 }
3030 }
3031
3032 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003033}
3034
3035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003036RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003037 NoHandleAllocation ha;
3038 ASSERT(args.length() == 2);
3039
3040 CONVERT_CHECKED(String, str1, args[0]);
3041 CONVERT_CHECKED(String, str2, args[1]);
3042
3043 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003044 int str1_length = str1->length();
3045 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003046
3047 // Decide trivial cases without flattening.
3048 if (str1_length == 0) {
3049 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3050 return Smi::FromInt(-str2_length);
3051 } else {
3052 if (str2_length == 0) return Smi::FromInt(str1_length);
3053 }
3054
3055 int end = str1_length < str2_length ? str1_length : str2_length;
3056
3057 // No need to flatten if we are going to find the answer on the first
3058 // character. At this point we know there is at least one character
3059 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003060 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003061 if (d != 0) return Smi::FromInt(d);
3062
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003063 str1->TryFlatten();
3064 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003065
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003066 StringInputBuffer& buf1 =
3067 *isolate->runtime_state()->string_locale_compare_buf1();
3068 StringInputBuffer& buf2 =
3069 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003070
3071 buf1.Reset(str1);
3072 buf2.Reset(str2);
3073
3074 for (int i = 0; i < end; i++) {
3075 uint16_t char1 = buf1.GetNext();
3076 uint16_t char2 = buf2.GetNext();
3077 if (char1 != char2) return Smi::FromInt(char1 - char2);
3078 }
3079
3080 return Smi::FromInt(str1_length - str2_length);
3081}
3082
3083
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003084RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003085 NoHandleAllocation ha;
3086 ASSERT(args.length() == 3);
3087
3088 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003089 Object* from = args[1];
3090 Object* to = args[2];
3091 int start, end;
3092 // We have a fast integer-only case here to avoid a conversion to double in
3093 // the common case where from and to are Smis.
3094 if (from->IsSmi() && to->IsSmi()) {
3095 start = Smi::cast(from)->value();
3096 end = Smi::cast(to)->value();
3097 } else {
3098 CONVERT_DOUBLE_CHECKED(from_number, from);
3099 CONVERT_DOUBLE_CHECKED(to_number, to);
3100 start = FastD2I(from_number);
3101 end = FastD2I(to_number);
3102 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003103 RUNTIME_ASSERT(end >= start);
3104 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003105 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003106 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003107 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003108}
3109
3110
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003111RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003112 ASSERT_EQ(3, args.length());
3113
3114 CONVERT_ARG_CHECKED(String, subject, 0);
3115 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3116 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3117 HandleScope handles;
3118
3119 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3120
3121 if (match.is_null()) {
3122 return Failure::Exception();
3123 }
3124 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003125 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003126 }
3127 int length = subject->length();
3128
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003129 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003130 ZoneList<int> offsets(8);
3131 do {
3132 int start;
3133 int end;
3134 {
3135 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003136 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003137 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3138 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3139 }
3140 offsets.Add(start);
3141 offsets.Add(end);
3142 int index = start < end ? end : end + 1;
3143 if (index > length) break;
3144 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3145 if (match.is_null()) {
3146 return Failure::Exception();
3147 }
3148 } while (!match->IsNull());
3149 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003150 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003151 for (int i = 0; i < matches ; i++) {
3152 int from = offsets.at(i * 2);
3153 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003154 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003155 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003156 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003157 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003158 result->set_length(Smi::FromInt(matches));
3159 return *result;
3160}
3161
3162
lrn@chromium.org25156de2010-04-06 13:10:27 +00003163// Two smis before and after the match, for very long strings.
3164const int kMaxBuilderEntriesPerRegExpMatch = 5;
3165
3166
3167static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3168 Handle<JSArray> last_match_info,
3169 int match_start,
3170 int match_end) {
3171 // Fill last_match_info with a single capture.
3172 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3173 AssertNoAllocation no_gc;
3174 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3175 RegExpImpl::SetLastCaptureCount(elements, 2);
3176 RegExpImpl::SetLastInput(elements, *subject);
3177 RegExpImpl::SetLastSubject(elements, *subject);
3178 RegExpImpl::SetCapture(elements, 0, match_start);
3179 RegExpImpl::SetCapture(elements, 1, match_end);
3180}
3181
3182
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003183template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003184static bool SearchStringMultiple(Isolate* isolate,
3185 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003186 Vector<const PatternChar> pattern,
3187 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003188 FixedArrayBuilder* builder,
3189 int* match_pos) {
3190 int pos = *match_pos;
3191 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003192 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003193 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003194 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003195 while (pos <= max_search_start) {
3196 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3197 *match_pos = pos;
3198 return false;
3199 }
3200 // Position of end of previous match.
3201 int match_end = pos + pattern_length;
3202 int new_pos = search.Search(subject, match_end);
3203 if (new_pos >= 0) {
3204 // A match.
3205 if (new_pos > match_end) {
3206 ReplacementStringBuilder::AddSubjectSlice(builder,
3207 match_end,
3208 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003209 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003210 pos = new_pos;
3211 builder->Add(pattern_string);
3212 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003213 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003214 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003215 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003216
lrn@chromium.org25156de2010-04-06 13:10:27 +00003217 if (pos < max_search_start) {
3218 ReplacementStringBuilder::AddSubjectSlice(builder,
3219 pos + pattern_length,
3220 subject_length);
3221 }
3222 *match_pos = pos;
3223 return true;
3224}
3225
3226
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003227static bool SearchStringMultiple(Isolate* isolate,
3228 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003229 Handle<String> pattern,
3230 Handle<JSArray> last_match_info,
3231 FixedArrayBuilder* builder) {
3232 ASSERT(subject->IsFlat());
3233 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003234
3235 // Treating as if a previous match was before first character.
3236 int match_pos = -pattern->length();
3237
3238 for (;;) { // Break when search complete.
3239 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3240 AssertNoAllocation no_gc;
3241 if (subject->IsAsciiRepresentation()) {
3242 Vector<const char> subject_vector = subject->ToAsciiVector();
3243 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003244 if (SearchStringMultiple(isolate,
3245 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003246 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003247 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003248 builder,
3249 &match_pos)) break;
3250 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003251 if (SearchStringMultiple(isolate,
3252 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003253 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003254 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003255 builder,
3256 &match_pos)) break;
3257 }
3258 } else {
3259 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3260 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003261 if (SearchStringMultiple(isolate,
3262 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003263 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003264 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003265 builder,
3266 &match_pos)) break;
3267 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003268 if (SearchStringMultiple(isolate,
3269 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003270 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003271 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003272 builder,
3273 &match_pos)) break;
3274 }
3275 }
3276 }
3277
3278 if (match_pos >= 0) {
3279 SetLastMatchInfoNoCaptures(subject,
3280 last_match_info,
3281 match_pos,
3282 match_pos + pattern->length());
3283 return true;
3284 }
3285 return false; // No matches at all.
3286}
3287
3288
3289static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003290 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003291 Handle<String> subject,
3292 Handle<JSRegExp> regexp,
3293 Handle<JSArray> last_match_array,
3294 FixedArrayBuilder* builder) {
3295 ASSERT(subject->IsFlat());
3296 int match_start = -1;
3297 int match_end = 0;
3298 int pos = 0;
3299 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3300 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3301
3302 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003303 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003304 int subject_length = subject->length();
3305
3306 for (;;) { // Break on failure, return on exception.
3307 RegExpImpl::IrregexpResult result =
3308 RegExpImpl::IrregexpExecOnce(regexp,
3309 subject,
3310 pos,
3311 register_vector);
3312 if (result == RegExpImpl::RE_SUCCESS) {
3313 match_start = register_vector[0];
3314 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3315 if (match_end < match_start) {
3316 ReplacementStringBuilder::AddSubjectSlice(builder,
3317 match_end,
3318 match_start);
3319 }
3320 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003321 HandleScope loop_scope(isolate);
3322 builder->Add(*isolate->factory()->NewSubString(subject,
3323 match_start,
3324 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003325 if (match_start != match_end) {
3326 pos = match_end;
3327 } else {
3328 pos = match_end + 1;
3329 if (pos > subject_length) break;
3330 }
3331 } else if (result == RegExpImpl::RE_FAILURE) {
3332 break;
3333 } else {
3334 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3335 return result;
3336 }
3337 }
3338
3339 if (match_start >= 0) {
3340 if (match_end < subject_length) {
3341 ReplacementStringBuilder::AddSubjectSlice(builder,
3342 match_end,
3343 subject_length);
3344 }
3345 SetLastMatchInfoNoCaptures(subject,
3346 last_match_array,
3347 match_start,
3348 match_end);
3349 return RegExpImpl::RE_SUCCESS;
3350 } else {
3351 return RegExpImpl::RE_FAILURE; // No matches at all.
3352 }
3353}
3354
3355
3356static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003357 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003358 Handle<String> subject,
3359 Handle<JSRegExp> regexp,
3360 Handle<JSArray> last_match_array,
3361 FixedArrayBuilder* builder) {
3362
3363 ASSERT(subject->IsFlat());
3364 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3365 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3366
3367 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003368 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003369
3370 RegExpImpl::IrregexpResult result =
3371 RegExpImpl::IrregexpExecOnce(regexp,
3372 subject,
3373 0,
3374 register_vector);
3375
3376 int capture_count = regexp->CaptureCount();
3377 int subject_length = subject->length();
3378
3379 // Position to search from.
3380 int pos = 0;
3381 // End of previous match. Differs from pos if match was empty.
3382 int match_end = 0;
3383 if (result == RegExpImpl::RE_SUCCESS) {
3384 // Need to keep a copy of the previous match for creating last_match_info
3385 // at the end, so we have two vectors that we swap between.
3386 OffsetsVector registers2(required_registers);
3387 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3388
3389 do {
3390 int match_start = register_vector[0];
3391 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3392 if (match_end < match_start) {
3393 ReplacementStringBuilder::AddSubjectSlice(builder,
3394 match_end,
3395 match_start);
3396 }
3397 match_end = register_vector[1];
3398
3399 {
3400 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003401 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003402 // Arguments array to replace function is match, captures, index and
3403 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003404 Handle<FixedArray> elements =
3405 isolate->factory()->NewFixedArray(3 + capture_count);
3406 Handle<String> match = isolate->factory()->NewSubString(subject,
3407 match_start,
3408 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003409 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003410 for (int i = 1; i <= capture_count; i++) {
3411 int start = register_vector[i * 2];
3412 if (start >= 0) {
3413 int end = register_vector[i * 2 + 1];
3414 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003415 Handle<String> substring = isolate->factory()->NewSubString(subject,
3416 start,
3417 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003418 elements->set(i, *substring);
3419 } else {
3420 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003421 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003422 }
3423 }
3424 elements->set(capture_count + 1, Smi::FromInt(match_start));
3425 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003426 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003427 }
3428 // Swap register vectors, so the last successful match is in
3429 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003430 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003431 prev_register_vector = register_vector;
3432 register_vector = tmp;
3433
3434 if (match_end > match_start) {
3435 pos = match_end;
3436 } else {
3437 pos = match_end + 1;
3438 if (pos > subject_length) {
3439 break;
3440 }
3441 }
3442
3443 result = RegExpImpl::IrregexpExecOnce(regexp,
3444 subject,
3445 pos,
3446 register_vector);
3447 } while (result == RegExpImpl::RE_SUCCESS);
3448
3449 if (result != RegExpImpl::RE_EXCEPTION) {
3450 // Finished matching, with at least one match.
3451 if (match_end < subject_length) {
3452 ReplacementStringBuilder::AddSubjectSlice(builder,
3453 match_end,
3454 subject_length);
3455 }
3456
3457 int last_match_capture_count = (capture_count + 1) * 2;
3458 int last_match_array_size =
3459 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3460 last_match_array->EnsureSize(last_match_array_size);
3461 AssertNoAllocation no_gc;
3462 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3463 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3464 RegExpImpl::SetLastSubject(elements, *subject);
3465 RegExpImpl::SetLastInput(elements, *subject);
3466 for (int i = 0; i < last_match_capture_count; i++) {
3467 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3468 }
3469 return RegExpImpl::RE_SUCCESS;
3470 }
3471 }
3472 // No matches at all, return failure or exception result directly.
3473 return result;
3474}
3475
3476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003477RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003478 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003479 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003480
3481 CONVERT_ARG_CHECKED(String, subject, 1);
3482 if (!subject->IsFlat()) { FlattenString(subject); }
3483 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3484 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3485 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3486
3487 ASSERT(last_match_info->HasFastElements());
3488 ASSERT(regexp->GetFlags().is_global());
3489 Handle<FixedArray> result_elements;
3490 if (result_array->HasFastElements()) {
3491 result_elements =
3492 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3493 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003494 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003495 }
3496 FixedArrayBuilder builder(result_elements);
3497
3498 if (regexp->TypeTag() == JSRegExp::ATOM) {
3499 Handle<String> pattern(
3500 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003501 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003502 if (SearchStringMultiple(isolate, subject, pattern,
3503 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003504 return *builder.ToJSArray(result_array);
3505 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003506 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003507 }
3508
3509 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3510
3511 RegExpImpl::IrregexpResult result;
3512 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003513 result = SearchRegExpNoCaptureMultiple(isolate,
3514 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003515 regexp,
3516 last_match_info,
3517 &builder);
3518 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003519 result = SearchRegExpMultiple(isolate,
3520 subject,
3521 regexp,
3522 last_match_info,
3523 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003524 }
3525 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003526 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003527 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3528 return Failure::Exception();
3529}
3530
3531
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003532RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003533 NoHandleAllocation ha;
3534 ASSERT(args.length() == 2);
3535
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003536 // Fast case where the result is a one character string.
3537 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3538 int value = Smi::cast(args[0])->value();
3539 int radix = Smi::cast(args[1])->value();
3540 if (value >= 0 && value < radix) {
3541 RUNTIME_ASSERT(radix <= 36);
3542 // Character array used for conversion.
3543 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003544 return isolate->heap()->
3545 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003546 }
3547 }
3548
3549 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003550 CONVERT_DOUBLE_CHECKED(value, args[0]);
3551 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003552 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003553 }
3554 if (isinf(value)) {
3555 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003556 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003557 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003558 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003559 }
3560 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3561 int radix = FastD2I(radix_number);
3562 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3563 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003564 MaybeObject* result =
3565 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003566 DeleteArray(str);
3567 return result;
3568}
3569
3570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003571RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003572 NoHandleAllocation ha;
3573 ASSERT(args.length() == 2);
3574
3575 CONVERT_DOUBLE_CHECKED(value, args[0]);
3576 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003577 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003578 }
3579 if (isinf(value)) {
3580 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003581 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003582 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003583 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003584 }
3585 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3586 int f = FastD2I(f_number);
3587 RUNTIME_ASSERT(f >= 0);
3588 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003589 MaybeObject* res =
3590 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003592 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003593}
3594
3595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003596RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 NoHandleAllocation ha;
3598 ASSERT(args.length() == 2);
3599
3600 CONVERT_DOUBLE_CHECKED(value, args[0]);
3601 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003602 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003603 }
3604 if (isinf(value)) {
3605 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003606 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003607 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003608 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003609 }
3610 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3611 int f = FastD2I(f_number);
3612 RUNTIME_ASSERT(f >= -1 && f <= 20);
3613 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003614 MaybeObject* res =
3615 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003617 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003618}
3619
3620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003621RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 NoHandleAllocation ha;
3623 ASSERT(args.length() == 2);
3624
3625 CONVERT_DOUBLE_CHECKED(value, args[0]);
3626 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003627 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003628 }
3629 if (isinf(value)) {
3630 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003631 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003632 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003633 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003634 }
3635 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3636 int f = FastD2I(f_number);
3637 RUNTIME_ASSERT(f >= 1 && f <= 21);
3638 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003639 MaybeObject* res =
3640 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003641 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003642 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643}
3644
3645
3646// Returns a single character string where first character equals
3647// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003648static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003649 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003650 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003651 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003652 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003654 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003655}
3656
3657
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003658MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3659 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003660 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 // Handle [] indexing on Strings
3662 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003663 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3664 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003665 }
3666
3667 // Handle [] indexing on String objects
3668 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003669 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3670 Handle<Object> result =
3671 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3672 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003673 }
3674
3675 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003676 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003677 return prototype->GetElement(index);
3678 }
3679
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003680 return GetElement(object, index);
3681}
3682
3683
lrn@chromium.org303ada72010-10-27 09:33:13 +00003684MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003685 return object->GetElement(index);
3686}
3687
3688
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003689MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3690 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003691 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003692 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003693
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003694 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003695 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003696 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003697 isolate->factory()->NewTypeError("non_object_property_load",
3698 HandleVector(args, 2));
3699 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003700 }
3701
3702 // Check if the given key is an array index.
3703 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003704 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003705 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003706 }
3707
3708 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003709 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003710 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003711 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003713 bool has_pending_exception = false;
3714 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003715 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003716 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003717 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003718 }
3719
ager@chromium.org32912102009-01-16 10:38:43 +00003720 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003721 // the element if so.
3722 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003723 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003724 } else {
3725 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003726 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003727 }
3728}
3729
3730
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003731RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003732 NoHandleAllocation ha;
3733 ASSERT(args.length() == 2);
3734
3735 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003736 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003737
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003738 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003739}
3740
3741
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003742// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003743RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003744 NoHandleAllocation ha;
3745 ASSERT(args.length() == 2);
3746
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003747 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003748 // itself.
3749 //
3750 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003751 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003752 // global proxy object never has properties. This is the case
3753 // because the global proxy object forwards everything to its hidden
3754 // prototype including local lookups.
3755 //
3756 // Additionally, we need to make sure that we do not cache results
3757 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003758 if (args[0]->IsJSObject() &&
3759 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003760 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003761 args[1]->IsString()) {
3762 JSObject* receiver = JSObject::cast(args[0]);
3763 String* key = String::cast(args[1]);
3764 if (receiver->HasFastProperties()) {
3765 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003766 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003767 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3768 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003769 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003770 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003771 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003772 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003773 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003774 LookupResult result;
3775 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003776 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003777 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003778 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003779 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003780 }
3781 } else {
3782 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003783 StringDictionary* dictionary = receiver->property_dictionary();
3784 int entry = dictionary->FindEntry(key);
3785 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003786 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003787 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003788 if (!receiver->IsGlobalObject()) return value;
3789 value = JSGlobalPropertyCell::cast(value)->value();
3790 if (!value->IsTheHole()) return value;
3791 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003792 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003793 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003794 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3795 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003796 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003797 Handle<String> str = args.at<String>(0);
3798 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003799 if (index >= 0 && index < str->length()) {
3800 Handle<Object> result = GetCharAt(str, index);
3801 return *result;
3802 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003803 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003804
3805 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003806 return Runtime::GetObjectProperty(isolate,
3807 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003808 args.at<Object>(1));
3809}
3810
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003811// Implements part of 8.12.9 DefineOwnProperty.
3812// There are 3 cases that lead here:
3813// Step 4b - define a new accessor property.
3814// Steps 9c & 12 - replace an existing data property with an accessor property.
3815// Step 12 - update an existing accessor property with an accessor or generic
3816// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003817RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003818 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003819 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003820 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3821 CONVERT_CHECKED(String, name, args[1]);
3822 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003823 Object* fun = args[3];
3824 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003825 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3826 int unchecked = flag_attr->value();
3827 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3828 RUNTIME_ASSERT(!obj->IsNull());
3829 LookupResult result;
3830 obj->LocalLookupRealNamedProperty(name, &result);
3831
3832 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3833 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3834 // delete it to avoid running into trouble in DefineAccessor, which
3835 // handles this incorrectly if the property is readonly (does nothing)
3836 if (result.IsProperty() &&
3837 (result.type() == FIELD || result.type() == NORMAL
3838 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003839 Object* ok;
3840 { MaybeObject* maybe_ok =
3841 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3842 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3843 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003844 }
3845 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3846}
3847
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003848// Implements part of 8.12.9 DefineOwnProperty.
3849// There are 3 cases that lead here:
3850// Step 4a - define a new data property.
3851// Steps 9b & 12 - replace an existing accessor property with a data property.
3852// Step 12 - update an existing data property with a data or generic
3853// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003854RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003855 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003856 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003857 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3858 CONVERT_ARG_CHECKED(String, name, 1);
3859 Handle<Object> obj_value = args.at<Object>(2);
3860
3861 CONVERT_CHECKED(Smi, flag, args[3]);
3862 int unchecked = flag->value();
3863 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3864
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003865 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3866
3867 // Check if this is an element.
3868 uint32_t index;
3869 bool is_element = name->AsArrayIndex(&index);
3870
3871 // Special case for elements if any of the flags are true.
3872 // If elements are in fast case we always implicitly assume that:
3873 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3874 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3875 is_element) {
3876 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003877 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003878 // We do not need to do access checks here since these has already
3879 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003880 Handle<Object> proto(js_object->GetPrototype());
3881 // If proxy is detached, ignore the assignment. Alternatively,
3882 // we could throw an exception.
3883 if (proto->IsNull()) return *obj_value;
3884 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003885 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003886 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003887 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003888 // Make sure that we never go back to fast case.
3889 dictionary->set_requires_slow_elements();
3890 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003891 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003892 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003893 }
3894
ager@chromium.org5c838252010-02-19 08:53:10 +00003895 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003896 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003897
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003898 // To be compatible with safari we do not change the value on API objects
3899 // in defineProperty. Firefox disagrees here, and actually changes the value.
3900 if (result.IsProperty() &&
3901 (result.type() == CALLBACKS) &&
3902 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003903 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003904 }
3905
ager@chromium.org5c838252010-02-19 08:53:10 +00003906 // Take special care when attributes are different and there is already
3907 // a property. For simplicity we normalize the property which enables us
3908 // to not worry about changing the instance_descriptor and creating a new
3909 // map. The current version of SetObjectProperty does not handle attributes
3910 // correctly in the case where a property is a field and is reset with
3911 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003912 if (result.IsProperty() &&
3913 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003914 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003915 if (js_object->IsJSGlobalProxy()) {
3916 // Since the result is a property, the prototype will exist so
3917 // we don't have to check for null.
3918 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003919 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003920 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003921 // Use IgnoreAttributes version since a readonly property may be
3922 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003923 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3924 *obj_value,
3925 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003926 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003927
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003928 return Runtime::ForceSetObjectProperty(isolate,
3929 js_object,
3930 name,
3931 obj_value,
3932 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003933}
3934
3935
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003936MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3937 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003938 Handle<Object> key,
3939 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003940 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003941 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003942 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003943
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003944 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003945 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003946 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003947 isolate->factory()->NewTypeError("non_object_property_store",
3948 HandleVector(args, 2));
3949 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003950 }
3951
3952 // If the object isn't a JavaScript object, we ignore the store.
3953 if (!object->IsJSObject()) return *value;
3954
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003955 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3956
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003957 // Check if the given key is an array index.
3958 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003959 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003960 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3961 // of a string using [] notation. We need to support this too in
3962 // JavaScript.
3963 // In the case of a String object we just need to redirect the assignment to
3964 // the underlying string if the index is in range. Since the underlying
3965 // string does nothing with the assignment then we can ignore such
3966 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003967 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003968 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003969 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003970
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003971 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003972 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003973 return *value;
3974 }
3975
3976 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003977 Handle<Object> result;
3978 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003979 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003980 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003981 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003982 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003983 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003984 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003985 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986 return *value;
3987 }
3988
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003989 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003990 bool has_pending_exception = false;
3991 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3992 if (has_pending_exception) return Failure::Exception();
3993 Handle<String> name = Handle<String>::cast(converted);
3994
3995 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003996 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003997 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003998 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003999 }
4000}
4001
4002
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004003MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4004 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004005 Handle<Object> key,
4006 Handle<Object> value,
4007 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004008 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004009
4010 // Check if the given key is an array index.
4011 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004012 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004013 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4014 // of a string using [] notation. We need to support this too in
4015 // JavaScript.
4016 // In the case of a String object we just need to redirect the assignment to
4017 // the underlying string if the index is in range. Since the underlying
4018 // string does nothing with the assignment then we can ignore such
4019 // assignments.
4020 if (js_object->IsStringObjectWithCharacterAt(index)) {
4021 return *value;
4022 }
4023
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004024 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004025 }
4026
4027 if (key->IsString()) {
4028 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004029 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004030 } else {
4031 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004032 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004033 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4034 *value,
4035 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004036 }
4037 }
4038
4039 // Call-back into JavaScript to convert the key to a string.
4040 bool has_pending_exception = false;
4041 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4042 if (has_pending_exception) return Failure::Exception();
4043 Handle<String> name = Handle<String>::cast(converted);
4044
4045 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004046 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004047 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004048 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004049 }
4050}
4051
4052
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004053MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4054 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004055 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004056 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004057
4058 // Check if the given key is an array index.
4059 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004060 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004061 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4062 // characters of a string using [] notation. In the case of a
4063 // String object we just need to redirect the deletion to the
4064 // underlying string if the index is in range. Since the
4065 // underlying string does nothing with the deletion, we can ignore
4066 // such deletions.
4067 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004068 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004069 }
4070
4071 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4072 }
4073
4074 Handle<String> key_string;
4075 if (key->IsString()) {
4076 key_string = Handle<String>::cast(key);
4077 } else {
4078 // Call-back into JavaScript to convert the key to a string.
4079 bool has_pending_exception = false;
4080 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4081 if (has_pending_exception) return Failure::Exception();
4082 key_string = Handle<String>::cast(converted);
4083 }
4084
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004085 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004086 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4087}
4088
4089
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004090RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004091 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004092 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093
4094 Handle<Object> object = args.at<Object>(0);
4095 Handle<Object> key = args.at<Object>(1);
4096 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004097 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4098 RUNTIME_ASSERT(
4099 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004101 PropertyAttributes attributes =
4102 static_cast<PropertyAttributes>(unchecked_attributes);
4103
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004104 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004105 if (args.length() == 5) {
4106 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4107 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4108 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004109 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004110 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004112 return Runtime::SetObjectProperty(isolate,
4113 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004114 key,
4115 value,
4116 attributes,
4117 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118}
4119
4120
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004121// Set the ES5 native flag on the function.
4122// This is used to decide if we should transform null and undefined
4123// into the global object when doing call and apply.
4124RUNTIME_FUNCTION(MaybeObject*, Runtime_SetES5Flag) {
4125 NoHandleAllocation ha;
4126 RUNTIME_ASSERT(args.length() == 1);
4127
4128 Handle<Object> object = args.at<Object>(0);
4129
4130 if (object->IsJSFunction()) {
4131 JSFunction* func = JSFunction::cast(*object);
4132 func->shared()->set_es5_native(true);
4133 }
4134 return isolate->heap()->undefined_value();
4135}
4136
4137
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004138// Set a local property, even if it is READ_ONLY. If the property does not
4139// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004140RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004141 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004142 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143 CONVERT_CHECKED(JSObject, object, args[0]);
4144 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004145 // Compute attributes.
4146 PropertyAttributes attributes = NONE;
4147 if (args.length() == 4) {
4148 CONVERT_CHECKED(Smi, value_obj, args[3]);
4149 int unchecked_value = value_obj->value();
4150 // Only attribute bits should be set.
4151 RUNTIME_ASSERT(
4152 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4153 attributes = static_cast<PropertyAttributes>(unchecked_value);
4154 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004155
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004156 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004157 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004158}
4159
4160
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004161RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004162 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004163 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164
4165 CONVERT_CHECKED(JSObject, object, args[0]);
4166 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004167 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004168 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004169 ? JSObject::STRICT_DELETION
4170 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004171}
4172
4173
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004174static Object* HasLocalPropertyImplementation(Isolate* isolate,
4175 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004176 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004177 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004178 // Handle hidden prototypes. If there's a hidden prototype above this thing
4179 // then we have to check it for properties, because they are supposed to
4180 // look like they are on this object.
4181 Handle<Object> proto(object->GetPrototype());
4182 if (proto->IsJSObject() &&
4183 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004184 return HasLocalPropertyImplementation(isolate,
4185 Handle<JSObject>::cast(proto),
4186 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004187 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004188 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004189}
4190
4191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004192RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004193 NoHandleAllocation ha;
4194 ASSERT(args.length() == 2);
4195 CONVERT_CHECKED(String, key, args[1]);
4196
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004197 uint32_t index;
4198 const bool key_is_array_index = key->AsArrayIndex(&index);
4199
ager@chromium.org9085a012009-05-11 19:22:57 +00004200 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004202 if (obj->IsJSObject()) {
4203 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004204 // Fast case: either the key is a real named property or it is not
4205 // an array index and there are no interceptors or hidden
4206 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004207 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004208 Map* map = object->map();
4209 if (!key_is_array_index &&
4210 !map->has_named_interceptor() &&
4211 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4212 return isolate->heap()->false_value();
4213 }
4214 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004215 HandleScope scope(isolate);
4216 return HasLocalPropertyImplementation(isolate,
4217 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004218 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004219 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004220 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004221 String* string = String::cast(obj);
4222 if (index < static_cast<uint32_t>(string->length())) {
4223 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004224 }
4225 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004226 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004227}
4228
4229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004230RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004231 NoHandleAllocation na;
4232 ASSERT(args.length() == 2);
4233
4234 // Only JS objects can have properties.
4235 if (args[0]->IsJSObject()) {
4236 JSObject* object = JSObject::cast(args[0]);
4237 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004238 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004239 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004240 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004241}
4242
4243
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004244RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004245 NoHandleAllocation na;
4246 ASSERT(args.length() == 2);
4247
4248 // Only JS objects can have elements.
4249 if (args[0]->IsJSObject()) {
4250 JSObject* object = JSObject::cast(args[0]);
4251 CONVERT_CHECKED(Smi, index_obj, args[1]);
4252 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004253 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004254 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004255 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004256}
4257
4258
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004259RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004260 NoHandleAllocation ha;
4261 ASSERT(args.length() == 2);
4262
4263 CONVERT_CHECKED(JSObject, object, args[0]);
4264 CONVERT_CHECKED(String, key, args[1]);
4265
4266 uint32_t index;
4267 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004268 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004269 }
4270
ager@chromium.org870a0b62008-11-04 11:43:05 +00004271 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004272 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004273}
4274
4275
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004276RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004277 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004278 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004279 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004280 return *GetKeysFor(object);
4281}
4282
4283
4284// Returns either a FixedArray as Runtime_GetPropertyNames,
4285// or, if the given object has an enum cache that contains
4286// all enumerable properties of the object and its prototypes
4287// have none, the map of the object. This is used to speed up
4288// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004289RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004290 ASSERT(args.length() == 1);
4291
4292 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4293
4294 if (raw_object->IsSimpleEnum()) return raw_object->map();
4295
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004296 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004297 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004298 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4299 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004300
4301 // Test again, since cache may have been built by preceding call.
4302 if (object->IsSimpleEnum()) return object->map();
4303
4304 return *content;
4305}
4306
4307
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004308// Find the length of the prototype chain that is to to handled as one. If a
4309// prototype object is hidden it is to be viewed as part of the the object it
4310// is prototype for.
4311static int LocalPrototypeChainLength(JSObject* obj) {
4312 int count = 1;
4313 Object* proto = obj->GetPrototype();
4314 while (proto->IsJSObject() &&
4315 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4316 count++;
4317 proto = JSObject::cast(proto)->GetPrototype();
4318 }
4319 return count;
4320}
4321
4322
4323// Return the names of the local named properties.
4324// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004325RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004326 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004327 ASSERT(args.length() == 1);
4328 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004329 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004330 }
4331 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4332
4333 // Skip the global proxy as it has no properties and always delegates to the
4334 // real global object.
4335 if (obj->IsJSGlobalProxy()) {
4336 // Only collect names if access is permitted.
4337 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004338 !isolate->MayNamedAccess(*obj,
4339 isolate->heap()->undefined_value(),
4340 v8::ACCESS_KEYS)) {
4341 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4342 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004343 }
4344 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4345 }
4346
4347 // Find the number of objects making up this.
4348 int length = LocalPrototypeChainLength(*obj);
4349
4350 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004351 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004352 int total_property_count = 0;
4353 Handle<JSObject> jsproto = obj;
4354 for (int i = 0; i < length; i++) {
4355 // Only collect names if access is permitted.
4356 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004357 !isolate->MayNamedAccess(*jsproto,
4358 isolate->heap()->undefined_value(),
4359 v8::ACCESS_KEYS)) {
4360 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4361 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004362 }
4363 int n;
4364 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4365 local_property_count[i] = n;
4366 total_property_count += n;
4367 if (i < length - 1) {
4368 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4369 }
4370 }
4371
4372 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004373 Handle<FixedArray> names =
4374 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004375
4376 // Get the property names.
4377 jsproto = obj;
4378 int proto_with_hidden_properties = 0;
4379 for (int i = 0; i < length; i++) {
4380 jsproto->GetLocalPropertyNames(*names,
4381 i == 0 ? 0 : local_property_count[i - 1]);
4382 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4383 proto_with_hidden_properties++;
4384 }
4385 if (i < length - 1) {
4386 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4387 }
4388 }
4389
4390 // Filter out name of hidden propeties object.
4391 if (proto_with_hidden_properties > 0) {
4392 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004393 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004394 names->length() - proto_with_hidden_properties);
4395 int dest_pos = 0;
4396 for (int i = 0; i < total_property_count; i++) {
4397 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004398 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004399 continue;
4400 }
4401 names->set(dest_pos++, name);
4402 }
4403 }
4404
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004405 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004406}
4407
4408
4409// Return the names of the local indexed properties.
4410// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004411RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004412 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004413 ASSERT(args.length() == 1);
4414 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004415 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004416 }
4417 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4418
4419 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004420 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004421 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004422 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004423}
4424
4425
4426// Return information on whether an object has a named or indexed interceptor.
4427// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004428RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004429 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004430 ASSERT(args.length() == 1);
4431 if (!args[0]->IsJSObject()) {
4432 return Smi::FromInt(0);
4433 }
4434 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4435
4436 int result = 0;
4437 if (obj->HasNamedInterceptor()) result |= 2;
4438 if (obj->HasIndexedInterceptor()) result |= 1;
4439
4440 return Smi::FromInt(result);
4441}
4442
4443
4444// Return property names from named interceptor.
4445// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004446RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004447 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004448 ASSERT(args.length() == 1);
4449 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4450
4451 if (obj->HasNamedInterceptor()) {
4452 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4453 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4454 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004455 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004456}
4457
4458
4459// Return element names from indexed interceptor.
4460// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004461RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004462 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004463 ASSERT(args.length() == 1);
4464 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4465
4466 if (obj->HasIndexedInterceptor()) {
4467 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4468 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4469 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004470 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004471}
4472
4473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004474RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004475 ASSERT_EQ(args.length(), 1);
4476 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004477 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004478 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004479
4480 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004481 // Do access checks before going to the global object.
4482 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004483 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004484 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004485 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4486 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004487 }
4488
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004489 Handle<Object> proto(object->GetPrototype());
4490 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004491 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004492 object = Handle<JSObject>::cast(proto);
4493 }
4494
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004495 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4496 LOCAL_ONLY);
4497 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4498 // property array and since the result is mutable we have to create
4499 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004500 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004501 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004502 for (int i = 0; i < length; i++) {
4503 Object* entry = contents->get(i);
4504 if (entry->IsString()) {
4505 copy->set(i, entry);
4506 } else {
4507 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004508 HandleScope scope(isolate);
4509 Handle<Object> entry_handle(entry, isolate);
4510 Handle<Object> entry_str =
4511 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004512 copy->set(i, *entry_str);
4513 }
4514 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004515 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004516}
4517
4518
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004519RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004520 NoHandleAllocation ha;
4521 ASSERT(args.length() == 1);
4522
4523 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004524 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004525 it.AdvanceToArgumentsFrame();
4526 JavaScriptFrame* frame = it.frame();
4527
4528 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004529 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004530
4531 // Try to convert the key to an index. If successful and within
4532 // index return the the argument from the frame.
4533 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004534 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004535 return frame->GetParameter(index);
4536 }
4537
4538 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004539 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004540 bool exception = false;
4541 Handle<Object> converted =
4542 Execution::ToString(args.at<Object>(0), &exception);
4543 if (exception) return Failure::Exception();
4544 Handle<String> key = Handle<String>::cast(converted);
4545
4546 // Try to convert the string key into an array index.
4547 if (key->AsArrayIndex(&index)) {
4548 if (index < n) {
4549 return frame->GetParameter(index);
4550 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004551 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004552 }
4553 }
4554
4555 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004556 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4557 if (key->Equals(isolate->heap()->callee_symbol())) {
4558 Object* function = frame->function();
4559 if (function->IsJSFunction() &&
4560 JSFunction::cast(function)->shared()->strict_mode()) {
4561 return isolate->Throw(*isolate->factory()->NewTypeError(
4562 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4563 }
4564 return function;
4565 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004566
4567 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004568 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004569}
4570
4571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004572RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004573 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004574
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004575 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004576 Handle<Object> object = args.at<Object>(0);
4577 if (object->IsJSObject()) {
4578 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004579 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004580 MaybeObject* ok = js_object->TransformToFastProperties(0);
4581 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004582 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004583 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004584 return *object;
4585}
4586
4587
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004588RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004589 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004590
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004591 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004592 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004593 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004594 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004595 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004596 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004597 return *object;
4598}
4599
4600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004601RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004602 NoHandleAllocation ha;
4603 ASSERT(args.length() == 1);
4604
4605 return args[0]->ToBoolean();
4606}
4607
4608
4609// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4610// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004611RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004612 NoHandleAllocation ha;
4613
4614 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004615 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616 HeapObject* heap_obj = HeapObject::cast(obj);
4617
4618 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004619 if (heap_obj->map()->is_undetectable()) {
4620 return isolate->heap()->undefined_symbol();
4621 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004622
4623 InstanceType instance_type = heap_obj->map()->instance_type();
4624 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004625 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004626 }
4627
4628 switch (instance_type) {
4629 case ODDBALL_TYPE:
4630 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004631 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004632 }
4633 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004634 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004635 }
4636 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004637 return isolate->heap()->undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004638 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004639 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004640 default:
4641 // For any kind of object not handled above, the spec rule for
4642 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004643 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004644 }
4645}
4646
4647
lrn@chromium.org25156de2010-04-06 13:10:27 +00004648static bool AreDigits(const char*s, int from, int to) {
4649 for (int i = from; i < to; i++) {
4650 if (s[i] < '0' || s[i] > '9') return false;
4651 }
4652
4653 return true;
4654}
4655
4656
4657static int ParseDecimalInteger(const char*s, int from, int to) {
4658 ASSERT(to - from < 10); // Overflow is not possible.
4659 ASSERT(from < to);
4660 int d = s[from] - '0';
4661
4662 for (int i = from + 1; i < to; i++) {
4663 d = 10 * d + (s[i] - '0');
4664 }
4665
4666 return d;
4667}
4668
4669
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004670RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004671 NoHandleAllocation ha;
4672 ASSERT(args.length() == 1);
4673 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004674 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004675
4676 // Fast case: short integer or some sorts of junk values.
4677 int len = subject->length();
4678 if (subject->IsSeqAsciiString()) {
4679 if (len == 0) return Smi::FromInt(0);
4680
4681 char const* data = SeqAsciiString::cast(subject)->GetChars();
4682 bool minus = (data[0] == '-');
4683 int start_pos = (minus ? 1 : 0);
4684
4685 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004686 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004687 } else if (data[start_pos] > '9') {
4688 // Fast check for a junk value. A valid string may start from a
4689 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4690 // the 'I' character ('Infinity'). All of that have codes not greater than
4691 // '9' except 'I'.
4692 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004693 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004694 }
4695 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4696 // The maximal/minimal smi has 10 digits. If the string has less digits we
4697 // know it will fit into the smi-data type.
4698 int d = ParseDecimalInteger(data, start_pos, len);
4699 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004700 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004701 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004702 } else if (!subject->HasHashCode() &&
4703 len <= String::kMaxArrayIndexSize &&
4704 (len == 1 || data[0] != '0')) {
4705 // String hash is not calculated yet but all the data are present.
4706 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004707 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004708#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004709 subject->Hash(); // Force hash calculation.
4710 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4711 static_cast<int>(hash));
4712#endif
4713 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004714 }
4715 return Smi::FromInt(d);
4716 }
4717 }
4718
4719 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004720 return isolate->heap()->NumberFromDouble(
4721 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004722}
4723
4724
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004725RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004726 NoHandleAllocation ha;
4727 ASSERT(args.length() == 1);
4728
4729 CONVERT_CHECKED(JSArray, codes, args[0]);
4730 int length = Smi::cast(codes->length())->value();
4731
4732 // Check if the string can be ASCII.
4733 int i;
4734 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004735 Object* element;
4736 { MaybeObject* maybe_element = codes->GetElement(i);
4737 // We probably can't get an exception here, but just in order to enforce
4738 // the checking of inputs in the runtime calls we check here.
4739 if (!maybe_element->ToObject(&element)) return maybe_element;
4740 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004741 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4742 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4743 break;
4744 }
4745
lrn@chromium.org303ada72010-10-27 09:33:13 +00004746 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004747 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004748 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004749 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004750 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004751 }
4752
lrn@chromium.org303ada72010-10-27 09:33:13 +00004753 Object* object = NULL;
4754 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004755 String* result = String::cast(object);
4756 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004757 Object* element;
4758 { MaybeObject* maybe_element = codes->GetElement(i);
4759 if (!maybe_element->ToObject(&element)) return maybe_element;
4760 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004761 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004762 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763 }
4764 return result;
4765}
4766
4767
4768// kNotEscaped is generated by the following:
4769//
4770// #!/bin/perl
4771// for (my $i = 0; $i < 256; $i++) {
4772// print "\n" if $i % 16 == 0;
4773// my $c = chr($i);
4774// my $escaped = 1;
4775// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4776// print $escaped ? "0, " : "1, ";
4777// }
4778
4779
4780static bool IsNotEscaped(uint16_t character) {
4781 // Only for 8 bit characters, the rest are always escaped (in a different way)
4782 ASSERT(character < 256);
4783 static const char kNotEscaped[256] = {
4784 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4785 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4786 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4787 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4788 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4789 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4790 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4791 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4792 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4793 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4794 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4795 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4796 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4797 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4798 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4799 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4800 };
4801 return kNotEscaped[character] != 0;
4802}
4803
4804
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004805RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004806 const char hex_chars[] = "0123456789ABCDEF";
4807 NoHandleAllocation ha;
4808 ASSERT(args.length() == 1);
4809 CONVERT_CHECKED(String, source, args[0]);
4810
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004811 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004812
4813 int escaped_length = 0;
4814 int length = source->length();
4815 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004816 Access<StringInputBuffer> buffer(
4817 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004818 buffer->Reset(source);
4819 while (buffer->has_more()) {
4820 uint16_t character = buffer->GetNext();
4821 if (character >= 256) {
4822 escaped_length += 6;
4823 } else if (IsNotEscaped(character)) {
4824 escaped_length++;
4825 } else {
4826 escaped_length += 3;
4827 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004828 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004829 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004830 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004831 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004832 return Failure::OutOfMemoryException();
4833 }
4834 }
4835 }
4836 // No length change implies no change. Return original string if no change.
4837 if (escaped_length == length) {
4838 return source;
4839 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004840 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004841 { MaybeObject* maybe_o =
4842 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004843 if (!maybe_o->ToObject(&o)) return maybe_o;
4844 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004845 String* destination = String::cast(o);
4846 int dest_position = 0;
4847
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004848 Access<StringInputBuffer> buffer(
4849 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004850 buffer->Rewind();
4851 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004852 uint16_t chr = buffer->GetNext();
4853 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004854 destination->Set(dest_position, '%');
4855 destination->Set(dest_position+1, 'u');
4856 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4857 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4858 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4859 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004860 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004861 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004862 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004863 dest_position++;
4864 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004865 destination->Set(dest_position, '%');
4866 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4867 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004868 dest_position += 3;
4869 }
4870 }
4871 return destination;
4872}
4873
4874
4875static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4876 static const signed char kHexValue['g'] = {
4877 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4878 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4879 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4880 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4881 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4882 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4883 -1, 10, 11, 12, 13, 14, 15 };
4884
4885 if (character1 > 'f') return -1;
4886 int hi = kHexValue[character1];
4887 if (hi == -1) return -1;
4888 if (character2 > 'f') return -1;
4889 int lo = kHexValue[character2];
4890 if (lo == -1) return -1;
4891 return (hi << 4) + lo;
4892}
4893
4894
ager@chromium.org870a0b62008-11-04 11:43:05 +00004895static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004896 int i,
4897 int length,
4898 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004899 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004900 int32_t hi = 0;
4901 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004902 if (character == '%' &&
4903 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004904 source->Get(i + 1) == 'u' &&
4905 (hi = TwoDigitHex(source->Get(i + 2),
4906 source->Get(i + 3))) != -1 &&
4907 (lo = TwoDigitHex(source->Get(i + 4),
4908 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004909 *step = 6;
4910 return (hi << 8) + lo;
4911 } else if (character == '%' &&
4912 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004913 (lo = TwoDigitHex(source->Get(i + 1),
4914 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004915 *step = 3;
4916 return lo;
4917 } else {
4918 *step = 1;
4919 return character;
4920 }
4921}
4922
4923
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004924RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004925 NoHandleAllocation ha;
4926 ASSERT(args.length() == 1);
4927 CONVERT_CHECKED(String, source, args[0]);
4928
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004929 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004930
4931 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004932 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004933
4934 int unescaped_length = 0;
4935 for (int i = 0; i < length; unescaped_length++) {
4936 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004937 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004938 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004939 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004940 i += step;
4941 }
4942
4943 // No length change implies no change. Return original string if no change.
4944 if (unescaped_length == length)
4945 return source;
4946
lrn@chromium.org303ada72010-10-27 09:33:13 +00004947 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004948 { MaybeObject* maybe_o =
4949 ascii ?
4950 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4951 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004952 if (!maybe_o->ToObject(&o)) return maybe_o;
4953 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004954 String* destination = String::cast(o);
4955
4956 int dest_position = 0;
4957 for (int i = 0; i < length; dest_position++) {
4958 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004959 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004960 i += step;
4961 }
4962 return destination;
4963}
4964
4965
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004966static const unsigned int kQuoteTableLength = 128u;
4967
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004968static const int kJsonQuotesCharactersPerEntry = 8;
4969static const char* const JsonQuotes =
4970 "\\u0000 \\u0001 \\u0002 \\u0003 "
4971 "\\u0004 \\u0005 \\u0006 \\u0007 "
4972 "\\b \\t \\n \\u000b "
4973 "\\f \\r \\u000e \\u000f "
4974 "\\u0010 \\u0011 \\u0012 \\u0013 "
4975 "\\u0014 \\u0015 \\u0016 \\u0017 "
4976 "\\u0018 \\u0019 \\u001a \\u001b "
4977 "\\u001c \\u001d \\u001e \\u001f "
4978 " ! \\\" # "
4979 "$ % & ' "
4980 "( ) * + "
4981 ", - . / "
4982 "0 1 2 3 "
4983 "4 5 6 7 "
4984 "8 9 : ; "
4985 "< = > ? "
4986 "@ A B C "
4987 "D E F G "
4988 "H I J K "
4989 "L M N O "
4990 "P Q R S "
4991 "T U V W "
4992 "X Y Z [ "
4993 "\\\\ ] ^ _ "
4994 "` a b c "
4995 "d e f g "
4996 "h i j k "
4997 "l m n o "
4998 "p q r s "
4999 "t u v w "
5000 "x y z { "
5001 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005002
5003
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005004// For a string that is less than 32k characters it should always be
5005// possible to allocate it in new space.
5006static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5007
5008
5009// Doing JSON quoting cannot make the string more than this many times larger.
5010static const int kJsonQuoteWorstCaseBlowup = 6;
5011
5012
5013// Covers the entire ASCII range (all other characters are unchanged by JSON
5014// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005015static const byte JsonQuoteLengths[kQuoteTableLength] = {
5016 6, 6, 6, 6, 6, 6, 6, 6,
5017 2, 2, 2, 6, 2, 2, 6, 6,
5018 6, 6, 6, 6, 6, 6, 6, 6,
5019 6, 6, 6, 6, 6, 6, 6, 6,
5020 1, 1, 2, 1, 1, 1, 1, 1,
5021 1, 1, 1, 1, 1, 1, 1, 1,
5022 1, 1, 1, 1, 1, 1, 1, 1,
5023 1, 1, 1, 1, 1, 1, 1, 1,
5024 1, 1, 1, 1, 1, 1, 1, 1,
5025 1, 1, 1, 1, 1, 1, 1, 1,
5026 1, 1, 1, 1, 1, 1, 1, 1,
5027 1, 1, 1, 1, 2, 1, 1, 1,
5028 1, 1, 1, 1, 1, 1, 1, 1,
5029 1, 1, 1, 1, 1, 1, 1, 1,
5030 1, 1, 1, 1, 1, 1, 1, 1,
5031 1, 1, 1, 1, 1, 1, 1, 1,
5032};
5033
5034
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005035template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005036MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005037
5038
5039template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005040MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5041 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005042}
5043
5044
5045template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005046MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5047 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005048}
5049
5050
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005051template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005052static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5053 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005054 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005055 const Char* read_cursor = characters.start();
5056 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005057 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005058 int quoted_length = kSpaceForQuotes;
5059 while (read_cursor < end) {
5060 Char c = *(read_cursor++);
5061 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5062 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005063 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005064 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005065 }
5066 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005067 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5068 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005069 Object* new_object;
5070 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005071 return new_alloc;
5072 }
5073 StringType* new_string = StringType::cast(new_object);
5074
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005075 Char* write_cursor = reinterpret_cast<Char*>(
5076 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005077 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005078 *(write_cursor++) = '"';
5079
5080 read_cursor = characters.start();
5081 while (read_cursor < end) {
5082 Char c = *(read_cursor++);
5083 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5084 *(write_cursor++) = c;
5085 } else {
5086 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5087 const char* replacement = JsonQuotes +
5088 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5089 for (int i = 0; i < len; i++) {
5090 *write_cursor++ = *replacement++;
5091 }
5092 }
5093 }
5094 *(write_cursor++) = '"';
5095 return new_string;
5096}
5097
5098
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005099template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005100static MaybeObject* QuoteJsonString(Isolate* isolate,
5101 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005102 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005103 isolate->counters()->quote_json_char_count()->Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005104 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005105 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
5106 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005107 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005108 }
5109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005110 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5111 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005112 Object* new_object;
5113 if (!new_alloc->ToObject(&new_object)) {
5114 return new_alloc;
5115 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005116 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005117 // Even if our string is small enough to fit in new space we still have to
5118 // handle it being allocated in old space as may happen in the third
5119 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5120 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005121 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005122 }
5123 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005124 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005125
5126 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5127 Char* write_cursor = reinterpret_cast<Char*>(
5128 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005129 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005130 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005131
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005132 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005133 const Char* end = read_cursor + length;
5134 while (read_cursor < end) {
5135 Char c = *(read_cursor++);
5136 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5137 *(write_cursor++) = c;
5138 } else {
5139 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5140 const char* replacement = JsonQuotes +
5141 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5142 write_cursor[0] = replacement[0];
5143 if (len > 1) {
5144 write_cursor[1] = replacement[1];
5145 if (len > 2) {
5146 ASSERT(len == 6);
5147 write_cursor[2] = replacement[2];
5148 write_cursor[3] = replacement[3];
5149 write_cursor[4] = replacement[4];
5150 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005151 }
5152 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005153 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005154 }
5155 }
5156 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005157
5158 int final_length = static_cast<int>(
5159 write_cursor - reinterpret_cast<Char*>(
5160 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005161 isolate->heap()->new_space()->
5162 template ShrinkStringAtAllocationBoundary<StringType>(
5163 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005164 return new_string;
5165}
5166
5167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005168RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005169 NoHandleAllocation ha;
5170 CONVERT_CHECKED(String, str, args[0]);
5171 if (!str->IsFlat()) {
5172 MaybeObject* try_flatten = str->TryFlatten();
5173 Object* flat;
5174 if (!try_flatten->ToObject(&flat)) {
5175 return try_flatten;
5176 }
5177 str = String::cast(flat);
5178 ASSERT(str->IsFlat());
5179 }
5180 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005181 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5182 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005183 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005184 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5185 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005186 }
5187}
5188
5189
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005190RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005191 NoHandleAllocation ha;
5192 CONVERT_CHECKED(String, str, args[0]);
5193 if (!str->IsFlat()) {
5194 MaybeObject* try_flatten = str->TryFlatten();
5195 Object* flat;
5196 if (!try_flatten->ToObject(&flat)) {
5197 return try_flatten;
5198 }
5199 str = String::cast(flat);
5200 ASSERT(str->IsFlat());
5201 }
5202 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005203 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5204 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005205 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005206 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5207 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005208 }
5209}
5210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005211RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005212 NoHandleAllocation ha;
5213
5214 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005215 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005216
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005217 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005218
lrn@chromium.org25156de2010-04-06 13:10:27 +00005219 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005220 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005221 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005222}
5223
5224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005225RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005226 NoHandleAllocation ha;
5227 CONVERT_CHECKED(String, str, args[0]);
5228
5229 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005230 double value = StringToDouble(isolate->unicode_cache(),
5231 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005232
5233 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005234 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005235}
5236
5237
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005238template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005239MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005240 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005241 String* s,
5242 int length,
5243 int input_string_length,
5244 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005245 // We try this twice, once with the assumption that the result is no longer
5246 // than the input and, if that assumption breaks, again with the exact
5247 // length. This may not be pretty, but it is nicer than what was here before
5248 // and I hereby claim my vaffel-is.
5249 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005250 // Allocate the resulting string.
5251 //
5252 // NOTE: This assumes that the upper/lower case of an ascii
5253 // character is also ascii. This is currently the case, but it
5254 // might break in the future if we implement more context and locale
5255 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005256 Object* o;
5257 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005258 ? isolate->heap()->AllocateRawAsciiString(length)
5259 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005260 if (!maybe_o->ToObject(&o)) return maybe_o;
5261 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005262 String* result = String::cast(o);
5263 bool has_changed_character = false;
5264
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005265 // Convert all characters to upper case, assuming that they will fit
5266 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005267 Access<StringInputBuffer> buffer(
5268 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005269 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005270 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005271 // We can assume that the string is not empty
5272 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005273 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005274 bool has_next = buffer->has_more();
5275 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005276 int char_length = mapping->get(current, next, chars);
5277 if (char_length == 0) {
5278 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005279 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005280 i++;
5281 } else if (char_length == 1) {
5282 // Common case: converting the letter resulted in one character.
5283 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005284 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005285 has_changed_character = true;
5286 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005287 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005288 // We've assumed that the result would be as long as the
5289 // input but here is a character that converts to several
5290 // characters. No matter, we calculate the exact length
5291 // of the result and try the whole thing again.
5292 //
5293 // Note that this leaves room for optimization. We could just
5294 // memcpy what we already have to the result string. Also,
5295 // the result string is the last object allocated we could
5296 // "realloc" it and probably, in the vast majority of cases,
5297 // extend the existing string to be able to hold the full
5298 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005299 int next_length = 0;
5300 if (has_next) {
5301 next_length = mapping->get(next, 0, chars);
5302 if (next_length == 0) next_length = 1;
5303 }
5304 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005305 while (buffer->has_more()) {
5306 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005307 // NOTE: we use 0 as the next character here because, while
5308 // the next character may affect what a character converts to,
5309 // it does not in any case affect the length of what it convert
5310 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005311 int char_length = mapping->get(current, 0, chars);
5312 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005313 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005314 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005315 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005316 return Failure::OutOfMemoryException();
5317 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005318 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005319 // Try again with the real length.
5320 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005321 } else {
5322 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005323 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005324 i++;
5325 }
5326 has_changed_character = true;
5327 }
5328 current = next;
5329 }
5330 if (has_changed_character) {
5331 return result;
5332 } else {
5333 // If we didn't actually change anything in doing the conversion
5334 // we simple return the result and let the converted string
5335 // become garbage; there is no reason to keep two identical strings
5336 // alive.
5337 return s;
5338 }
5339}
5340
5341
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005342namespace {
5343
lrn@chromium.org303ada72010-10-27 09:33:13 +00005344static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5345
5346
5347// Given a word and two range boundaries returns a word with high bit
5348// set in every byte iff the corresponding input byte was strictly in
5349// the range (m, n). All the other bits in the result are cleared.
5350// This function is only useful when it can be inlined and the
5351// boundaries are statically known.
5352// Requires: all bytes in the input word and the boundaries must be
5353// ascii (less than 0x7F).
5354static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5355 // Every byte in an ascii string is less than or equal to 0x7F.
5356 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5357 // Use strict inequalities since in edge cases the function could be
5358 // further simplified.
5359 ASSERT(0 < m && m < n && n < 0x7F);
5360 // Has high bit set in every w byte less than n.
5361 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5362 // Has high bit set in every w byte greater than m.
5363 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5364 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5365}
5366
5367
5368enum AsciiCaseConversion {
5369 ASCII_TO_LOWER,
5370 ASCII_TO_UPPER
5371};
5372
5373
5374template <AsciiCaseConversion dir>
5375struct FastAsciiConverter {
5376 static bool Convert(char* dst, char* src, int length) {
5377#ifdef DEBUG
5378 char* saved_dst = dst;
5379 char* saved_src = src;
5380#endif
5381 // We rely on the distance between upper and lower case letters
5382 // being a known power of 2.
5383 ASSERT('a' - 'A' == (1 << 5));
5384 // Boundaries for the range of input characters than require conversion.
5385 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5386 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5387 bool changed = false;
5388 char* const limit = src + length;
5389#ifdef V8_HOST_CAN_READ_UNALIGNED
5390 // Process the prefix of the input that requires no conversion one
5391 // (machine) word at a time.
5392 while (src <= limit - sizeof(uintptr_t)) {
5393 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5394 if (AsciiRangeMask(w, lo, hi) != 0) {
5395 changed = true;
5396 break;
5397 }
5398 *reinterpret_cast<uintptr_t*>(dst) = w;
5399 src += sizeof(uintptr_t);
5400 dst += sizeof(uintptr_t);
5401 }
5402 // Process the remainder of the input performing conversion when
5403 // required one word at a time.
5404 while (src <= limit - sizeof(uintptr_t)) {
5405 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5406 uintptr_t m = AsciiRangeMask(w, lo, hi);
5407 // The mask has high (7th) bit set in every byte that needs
5408 // conversion and we know that the distance between cases is
5409 // 1 << 5.
5410 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5411 src += sizeof(uintptr_t);
5412 dst += sizeof(uintptr_t);
5413 }
5414#endif
5415 // Process the last few bytes of the input (or the whole input if
5416 // unaligned access is not supported).
5417 while (src < limit) {
5418 char c = *src;
5419 if (lo < c && c < hi) {
5420 c ^= (1 << 5);
5421 changed = true;
5422 }
5423 *dst = c;
5424 ++src;
5425 ++dst;
5426 }
5427#ifdef DEBUG
5428 CheckConvert(saved_dst, saved_src, length, changed);
5429#endif
5430 return changed;
5431 }
5432
5433#ifdef DEBUG
5434 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5435 bool expected_changed = false;
5436 for (int i = 0; i < length; i++) {
5437 if (dst[i] == src[i]) continue;
5438 expected_changed = true;
5439 if (dir == ASCII_TO_LOWER) {
5440 ASSERT('A' <= src[i] && src[i] <= 'Z');
5441 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5442 } else {
5443 ASSERT(dir == ASCII_TO_UPPER);
5444 ASSERT('a' <= src[i] && src[i] <= 'z');
5445 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5446 }
5447 }
5448 ASSERT(expected_changed == changed);
5449 }
5450#endif
5451};
5452
5453
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005454struct ToLowerTraits {
5455 typedef unibrow::ToLowercase UnibrowConverter;
5456
lrn@chromium.org303ada72010-10-27 09:33:13 +00005457 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005458};
5459
5460
5461struct ToUpperTraits {
5462 typedef unibrow::ToUppercase UnibrowConverter;
5463
lrn@chromium.org303ada72010-10-27 09:33:13 +00005464 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005465};
5466
5467} // namespace
5468
5469
5470template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005471MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005472 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005473 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005474 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005475 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005476 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005477 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005478
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005479 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005480 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005481 if (length == 0) return s;
5482
5483 // Simpler handling of ascii strings.
5484 //
5485 // NOTE: This assumes that the upper/lower case of an ascii
5486 // character is also ascii. This is currently the case, but it
5487 // might break in the future if we implement more context and locale
5488 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005489 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005490 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005491 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005492 if (!maybe_o->ToObject(&o)) return maybe_o;
5493 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005494 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005495 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005496 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005497 return has_changed_character ? result : s;
5498 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005499
lrn@chromium.org303ada72010-10-27 09:33:13 +00005500 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005501 { MaybeObject* maybe_answer =
5502 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005503 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5504 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005505 if (answer->IsSmi()) {
5506 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005507 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005508 ConvertCaseHelper(isolate,
5509 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005510 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5511 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005512 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005513 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005514}
5515
5516
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005517RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005518 return ConvertCase<ToLowerTraits>(
5519 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005520}
5521
5522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005523RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005524 return ConvertCase<ToUpperTraits>(
5525 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005526}
5527
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005528
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005529static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5530 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5531}
5532
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005534RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005535 NoHandleAllocation ha;
5536 ASSERT(args.length() == 3);
5537
5538 CONVERT_CHECKED(String, s, args[0]);
5539 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5540 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5541
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005542 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005543 int length = s->length();
5544
5545 int left = 0;
5546 if (trimLeft) {
5547 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5548 left++;
5549 }
5550 }
5551
5552 int right = length;
5553 if (trimRight) {
5554 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5555 right--;
5556 }
5557 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005558 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005559}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005560
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005561
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005562template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005563void FindStringIndices(Isolate* isolate,
5564 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005565 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005566 ZoneList<int>* indices,
5567 unsigned int limit) {
5568 ASSERT(limit > 0);
5569 // Collect indices of pattern in subject, and the end-of-string index.
5570 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005571 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005572 int pattern_length = pattern.length();
5573 int index = 0;
5574 while (limit > 0) {
5575 index = search.Search(subject, index);
5576 if (index < 0) return;
5577 indices->Add(index);
5578 index += pattern_length;
5579 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005580 }
5581}
5582
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005583
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005584RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005585 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005586 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005587 CONVERT_ARG_CHECKED(String, subject, 0);
5588 CONVERT_ARG_CHECKED(String, pattern, 1);
5589 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5590
5591 int subject_length = subject->length();
5592 int pattern_length = pattern->length();
5593 RUNTIME_ASSERT(pattern_length > 0);
5594
5595 // The limit can be very large (0xffffffffu), but since the pattern
5596 // isn't empty, we can never create more parts than ~half the length
5597 // of the subject.
5598
5599 if (!subject->IsFlat()) FlattenString(subject);
5600
5601 static const int kMaxInitialListCapacity = 16;
5602
5603 ZoneScope scope(DELETE_ON_EXIT);
5604
5605 // Find (up to limit) indices of separator and end-of-string in subject
5606 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5607 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005608 if (!pattern->IsFlat()) FlattenString(pattern);
5609
5610 // No allocation block.
5611 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005612 AssertNoAllocation nogc;
5613 if (subject->IsAsciiRepresentation()) {
5614 Vector<const char> subject_vector = subject->ToAsciiVector();
5615 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005616 FindStringIndices(isolate,
5617 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005618 pattern->ToAsciiVector(),
5619 &indices,
5620 limit);
5621 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005622 FindStringIndices(isolate,
5623 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005624 pattern->ToUC16Vector(),
5625 &indices,
5626 limit);
5627 }
5628 } else {
5629 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5630 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005631 FindStringIndices(isolate,
5632 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005633 pattern->ToAsciiVector(),
5634 &indices,
5635 limit);
5636 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005637 FindStringIndices(isolate,
5638 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005639 pattern->ToUC16Vector(),
5640 &indices,
5641 limit);
5642 }
5643 }
5644 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005645
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005646 if (static_cast<uint32_t>(indices.length()) < limit) {
5647 indices.Add(subject_length);
5648 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005649
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005650 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005651
5652 // Create JSArray of substrings separated by separator.
5653 int part_count = indices.length();
5654
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005655 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005656 result->set_length(Smi::FromInt(part_count));
5657
5658 ASSERT(result->HasFastElements());
5659
5660 if (part_count == 1 && indices.at(0) == subject_length) {
5661 FixedArray::cast(result->elements())->set(0, *subject);
5662 return *result;
5663 }
5664
5665 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5666 int part_start = 0;
5667 for (int i = 0; i < part_count; i++) {
5668 HandleScope local_loop_handle;
5669 int part_end = indices.at(i);
5670 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005671 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005672 elements->set(i, *substring);
5673 part_start = part_end + pattern_length;
5674 }
5675
5676 return *result;
5677}
5678
5679
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005680// Copies ascii characters to the given fixed array looking up
5681// one-char strings in the cache. Gives up on the first char that is
5682// not in the cache and fills the remainder with smi zeros. Returns
5683// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005684static int CopyCachedAsciiCharsToArray(Heap* heap,
5685 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005686 FixedArray* elements,
5687 int length) {
5688 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005689 FixedArray* ascii_cache = heap->single_character_string_cache();
5690 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005691 int i;
5692 for (i = 0; i < length; ++i) {
5693 Object* value = ascii_cache->get(chars[i]);
5694 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005695 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005696 elements->set(i, value, SKIP_WRITE_BARRIER);
5697 }
5698 if (i < length) {
5699 ASSERT(Smi::FromInt(0) == 0);
5700 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5701 }
5702#ifdef DEBUG
5703 for (int j = 0; j < length; ++j) {
5704 Object* element = elements->get(j);
5705 ASSERT(element == Smi::FromInt(0) ||
5706 (element->IsString() && String::cast(element)->LooksValid()));
5707 }
5708#endif
5709 return i;
5710}
5711
5712
5713// Converts a String to JSArray.
5714// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005715RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005716 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005717 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005718 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005719 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005720
5721 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005722 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005723
5724 Handle<FixedArray> elements;
5725 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005726 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005727 { MaybeObject* maybe_obj =
5728 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005729 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5730 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005731 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005732
5733 Vector<const char> chars = s->ToAsciiVector();
5734 // Note, this will initialize all elements (not only the prefix)
5735 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005736 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5737 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005738 *elements,
5739 length);
5740
5741 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005742 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5743 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005744 }
5745 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005746 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005747 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005748 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5749 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005750 }
5751 }
5752
5753#ifdef DEBUG
5754 for (int i = 0; i < length; ++i) {
5755 ASSERT(String::cast(elements->get(i))->length() == 1);
5756 }
5757#endif
5758
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005759 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005760}
5761
5762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005763RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005764 NoHandleAllocation ha;
5765 ASSERT(args.length() == 1);
5766 CONVERT_CHECKED(String, value, args[0]);
5767 return value->ToObject();
5768}
5769
5770
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005771bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005772 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005773 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005774 return char_length == 0;
5775}
5776
5777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005778RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005779 NoHandleAllocation ha;
5780 ASSERT(args.length() == 1);
5781
5782 Object* number = args[0];
5783 RUNTIME_ASSERT(number->IsNumber());
5784
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005785 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005786}
5787
5788
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005789RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005790 NoHandleAllocation ha;
5791 ASSERT(args.length() == 1);
5792
5793 Object* number = args[0];
5794 RUNTIME_ASSERT(number->IsNumber());
5795
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005796 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005797}
5798
5799
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005800RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005801 NoHandleAllocation ha;
5802 ASSERT(args.length() == 1);
5803
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005804 CONVERT_DOUBLE_CHECKED(number, args[0]);
5805
5806 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5807 if (number > 0 && number <= Smi::kMaxValue) {
5808 return Smi::FromInt(static_cast<int>(number));
5809 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005810 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005811}
5812
5813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005814RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005815 NoHandleAllocation ha;
5816 ASSERT(args.length() == 1);
5817
5818 CONVERT_DOUBLE_CHECKED(number, args[0]);
5819
5820 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5821 if (number > 0 && number <= Smi::kMaxValue) {
5822 return Smi::FromInt(static_cast<int>(number));
5823 }
5824
5825 double double_value = DoubleToInteger(number);
5826 // Map both -0 and +0 to +0.
5827 if (double_value == 0) double_value = 0;
5828
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005829 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005830}
5831
5832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005833RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005834 NoHandleAllocation ha;
5835 ASSERT(args.length() == 1);
5836
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005837 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005838 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005839}
5840
5841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005842RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005843 NoHandleAllocation ha;
5844 ASSERT(args.length() == 1);
5845
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005846 CONVERT_DOUBLE_CHECKED(number, args[0]);
5847
5848 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5849 if (number > 0 && number <= Smi::kMaxValue) {
5850 return Smi::FromInt(static_cast<int>(number));
5851 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005852 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005853}
5854
5855
ager@chromium.org870a0b62008-11-04 11:43:05 +00005856// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5857// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005858RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005859 NoHandleAllocation ha;
5860 ASSERT(args.length() == 1);
5861
5862 Object* obj = args[0];
5863 if (obj->IsSmi()) {
5864 return obj;
5865 }
5866 if (obj->IsHeapNumber()) {
5867 double value = HeapNumber::cast(obj)->value();
5868 int int_value = FastD2I(value);
5869 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5870 return Smi::FromInt(int_value);
5871 }
5872 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005873 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005874}
5875
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005877RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005878 NoHandleAllocation ha;
5879 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005880 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005881}
5882
5883
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005884RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005885 NoHandleAllocation ha;
5886 ASSERT(args.length() == 2);
5887
5888 CONVERT_DOUBLE_CHECKED(x, args[0]);
5889 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005890 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005891}
5892
5893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005894RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005895 NoHandleAllocation ha;
5896 ASSERT(args.length() == 2);
5897
5898 CONVERT_DOUBLE_CHECKED(x, args[0]);
5899 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005900 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005901}
5902
5903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005904RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005905 NoHandleAllocation ha;
5906 ASSERT(args.length() == 2);
5907
5908 CONVERT_DOUBLE_CHECKED(x, args[0]);
5909 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005910 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005911}
5912
5913
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005914RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005915 NoHandleAllocation ha;
5916 ASSERT(args.length() == 1);
5917
5918 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005919 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005920}
5921
5922
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005923RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005924 NoHandleAllocation ha;
5925 ASSERT(args.length() == 0);
5926
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005927 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005928}
5929
5930
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005931RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005932 NoHandleAllocation ha;
5933 ASSERT(args.length() == 2);
5934
5935 CONVERT_DOUBLE_CHECKED(x, args[0]);
5936 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005937 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005938}
5939
5940
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005941RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005942 NoHandleAllocation ha;
5943 ASSERT(args.length() == 2);
5944
5945 CONVERT_DOUBLE_CHECKED(x, args[0]);
5946 CONVERT_DOUBLE_CHECKED(y, args[1]);
5947
ager@chromium.org3811b432009-10-28 14:53:37 +00005948 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005949 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005950 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005951}
5952
5953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005954RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005955 NoHandleAllocation ha;
5956 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005957 CONVERT_CHECKED(String, str1, args[0]);
5958 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005959 isolate->counters()->string_add_runtime()->Increment();
5960 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005961}
5962
5963
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005964template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005965static inline void StringBuilderConcatHelper(String* special,
5966 sinkchar* sink,
5967 FixedArray* fixed_array,
5968 int array_length) {
5969 int position = 0;
5970 for (int i = 0; i < array_length; i++) {
5971 Object* element = fixed_array->get(i);
5972 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005973 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005974 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005975 int pos;
5976 int len;
5977 if (encoded_slice > 0) {
5978 // Position and length encoded in one smi.
5979 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5980 len = StringBuilderSubstringLength::decode(encoded_slice);
5981 } else {
5982 // Position and length encoded in two smis.
5983 Object* obj = fixed_array->get(++i);
5984 ASSERT(obj->IsSmi());
5985 pos = Smi::cast(obj)->value();
5986 len = -encoded_slice;
5987 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005988 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005989 sink + position,
5990 pos,
5991 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005992 position += len;
5993 } else {
5994 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005995 int element_length = string->length();
5996 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005997 position += element_length;
5998 }
5999 }
6000}
6001
6002
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006003RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006004 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006005 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006006 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006007 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006008 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006009 return Failure::OutOfMemoryException();
6010 }
6011 int array_length = Smi::cast(args[1])->value();
6012 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006013
6014 // This assumption is used by the slice encoding in one or two smis.
6015 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6016
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006017 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006018 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006019 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006020 }
6021 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006022 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006023 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006024 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006025
6026 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006027 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006028 } else if (array_length == 1) {
6029 Object* first = fixed_array->get(0);
6030 if (first->IsString()) return first;
6031 }
6032
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006033 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006034 int position = 0;
6035 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006036 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006037 Object* elt = fixed_array->get(i);
6038 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006039 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006040 int smi_value = Smi::cast(elt)->value();
6041 int pos;
6042 int len;
6043 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006044 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006045 pos = StringBuilderSubstringPosition::decode(smi_value);
6046 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006047 } else {
6048 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006049 len = -smi_value;
6050 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006051 i++;
6052 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006053 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006054 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006055 Object* next_smi = fixed_array->get(i);
6056 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006057 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006058 }
6059 pos = Smi::cast(next_smi)->value();
6060 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006061 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006062 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006063 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006064 ASSERT(pos >= 0);
6065 ASSERT(len >= 0);
6066 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006067 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006068 }
6069 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006070 } else if (elt->IsString()) {
6071 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006072 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006073 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006074 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006075 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006076 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006077 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006078 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006079 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006080 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006081 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006082 return Failure::OutOfMemoryException();
6083 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006084 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006085 }
6086
6087 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006088 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006089
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006090 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006091 { MaybeObject* maybe_object =
6092 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006093 if (!maybe_object->ToObject(&object)) return maybe_object;
6094 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006095 SeqAsciiString* answer = SeqAsciiString::cast(object);
6096 StringBuilderConcatHelper(special,
6097 answer->GetChars(),
6098 fixed_array,
6099 array_length);
6100 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006101 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006102 { MaybeObject* maybe_object =
6103 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006104 if (!maybe_object->ToObject(&object)) return maybe_object;
6105 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006106 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6107 StringBuilderConcatHelper(special,
6108 answer->GetChars(),
6109 fixed_array,
6110 array_length);
6111 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006112 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006113}
6114
6115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006116RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006117 NoHandleAllocation ha;
6118 ASSERT(args.length() == 3);
6119 CONVERT_CHECKED(JSArray, array, args[0]);
6120 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006121 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006122 return Failure::OutOfMemoryException();
6123 }
6124 int array_length = Smi::cast(args[1])->value();
6125 CONVERT_CHECKED(String, separator, args[2]);
6126
6127 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006128 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006129 }
6130 FixedArray* fixed_array = FixedArray::cast(array->elements());
6131 if (fixed_array->length() < array_length) {
6132 array_length = fixed_array->length();
6133 }
6134
6135 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006136 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006137 } else if (array_length == 1) {
6138 Object* first = fixed_array->get(0);
6139 if (first->IsString()) return first;
6140 }
6141
6142 int separator_length = separator->length();
6143 int max_nof_separators =
6144 (String::kMaxLength + separator_length - 1) / separator_length;
6145 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006146 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006147 return Failure::OutOfMemoryException();
6148 }
6149 int length = (array_length - 1) * separator_length;
6150 for (int i = 0; i < array_length; i++) {
6151 Object* element_obj = fixed_array->get(i);
6152 if (!element_obj->IsString()) {
6153 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006154 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006155 }
6156 String* element = String::cast(element_obj);
6157 int increment = element->length();
6158 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006159 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006160 return Failure::OutOfMemoryException();
6161 }
6162 length += increment;
6163 }
6164
6165 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006166 { MaybeObject* maybe_object =
6167 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006168 if (!maybe_object->ToObject(&object)) return maybe_object;
6169 }
6170 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6171
6172 uc16* sink = answer->GetChars();
6173#ifdef DEBUG
6174 uc16* end = sink + length;
6175#endif
6176
6177 String* first = String::cast(fixed_array->get(0));
6178 int first_length = first->length();
6179 String::WriteToFlat(first, sink, 0, first_length);
6180 sink += first_length;
6181
6182 for (int i = 1; i < array_length; i++) {
6183 ASSERT(sink + separator_length <= end);
6184 String::WriteToFlat(separator, sink, 0, separator_length);
6185 sink += separator_length;
6186
6187 String* element = String::cast(fixed_array->get(i));
6188 int element_length = element->length();
6189 ASSERT(sink + element_length <= end);
6190 String::WriteToFlat(element, sink, 0, element_length);
6191 sink += element_length;
6192 }
6193 ASSERT(sink == end);
6194
6195 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6196 return answer;
6197}
6198
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006199template <typename Char>
6200static void JoinSparseArrayWithSeparator(FixedArray* elements,
6201 int elements_length,
6202 uint32_t array_length,
6203 String* separator,
6204 Vector<Char> buffer) {
6205 int previous_separator_position = 0;
6206 int separator_length = separator->length();
6207 int cursor = 0;
6208 for (int i = 0; i < elements_length; i += 2) {
6209 int position = NumberToInt32(elements->get(i));
6210 String* string = String::cast(elements->get(i + 1));
6211 int string_length = string->length();
6212 if (string->length() > 0) {
6213 while (previous_separator_position < position) {
6214 String::WriteToFlat<Char>(separator, &buffer[cursor],
6215 0, separator_length);
6216 cursor += separator_length;
6217 previous_separator_position++;
6218 }
6219 String::WriteToFlat<Char>(string, &buffer[cursor],
6220 0, string_length);
6221 cursor += string->length();
6222 }
6223 }
6224 if (separator_length > 0) {
6225 // Array length must be representable as a signed 32-bit number,
6226 // otherwise the total string length would have been too large.
6227 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6228 int last_array_index = static_cast<int>(array_length - 1);
6229 while (previous_separator_position < last_array_index) {
6230 String::WriteToFlat<Char>(separator, &buffer[cursor],
6231 0, separator_length);
6232 cursor += separator_length;
6233 previous_separator_position++;
6234 }
6235 }
6236 ASSERT(cursor <= buffer.length());
6237}
6238
6239
6240RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6241 NoHandleAllocation ha;
6242 ASSERT(args.length() == 3);
6243 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6244 RUNTIME_ASSERT(elements_array->HasFastElements());
6245 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6246 CONVERT_CHECKED(String, separator, args[2]);
6247 // elements_array is fast-mode JSarray of alternating positions
6248 // (increasing order) and strings.
6249 // array_length is length of original array (used to add separators);
6250 // separator is string to put between elements. Assumed to be non-empty.
6251
6252 // Find total length of join result.
6253 int string_length = 0;
6254 bool is_ascii = true;
6255 int max_string_length = SeqAsciiString::kMaxLength;
6256 bool overflow = false;
6257 CONVERT_NUMBER_CHECKED(int, elements_length,
6258 Int32, elements_array->length());
6259 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6260 FixedArray* elements = FixedArray::cast(elements_array->elements());
6261 for (int i = 0; i < elements_length; i += 2) {
6262 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6263 CONVERT_CHECKED(String, string, elements->get(i + 1));
6264 int length = string->length();
6265 if (is_ascii && !string->IsAsciiRepresentation()) {
6266 is_ascii = false;
6267 max_string_length = SeqTwoByteString::kMaxLength;
6268 }
6269 if (length > max_string_length ||
6270 max_string_length - length < string_length) {
6271 overflow = true;
6272 break;
6273 }
6274 string_length += length;
6275 }
6276 int separator_length = separator->length();
6277 if (!overflow && separator_length > 0) {
6278 if (array_length <= 0x7fffffffu) {
6279 int separator_count = static_cast<int>(array_length) - 1;
6280 int remaining_length = max_string_length - string_length;
6281 if ((remaining_length / separator_length) >= separator_count) {
6282 string_length += separator_length * (array_length - 1);
6283 } else {
6284 // Not room for the separators within the maximal string length.
6285 overflow = true;
6286 }
6287 } else {
6288 // Nonempty separator and at least 2^31-1 separators necessary
6289 // means that the string is too large to create.
6290 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6291 overflow = true;
6292 }
6293 }
6294 if (overflow) {
6295 // Throw OutOfMemory exception for creating too large a string.
6296 V8::FatalProcessOutOfMemory("Array join result too large.");
6297 }
6298
6299 if (is_ascii) {
6300 MaybeObject* result_allocation =
6301 isolate->heap()->AllocateRawAsciiString(string_length);
6302 if (result_allocation->IsFailure()) return result_allocation;
6303 SeqAsciiString* result_string =
6304 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6305 JoinSparseArrayWithSeparator<char>(elements,
6306 elements_length,
6307 array_length,
6308 separator,
6309 Vector<char>(result_string->GetChars(),
6310 string_length));
6311 return result_string;
6312 } else {
6313 MaybeObject* result_allocation =
6314 isolate->heap()->AllocateRawTwoByteString(string_length);
6315 if (result_allocation->IsFailure()) return result_allocation;
6316 SeqTwoByteString* result_string =
6317 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6318 JoinSparseArrayWithSeparator<uc16>(elements,
6319 elements_length,
6320 array_length,
6321 separator,
6322 Vector<uc16>(result_string->GetChars(),
6323 string_length));
6324 return result_string;
6325 }
6326}
6327
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006328
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006329RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006330 NoHandleAllocation ha;
6331 ASSERT(args.length() == 2);
6332
6333 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6334 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006335 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006336}
6337
6338
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006339RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006340 NoHandleAllocation ha;
6341 ASSERT(args.length() == 2);
6342
6343 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6344 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006345 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006346}
6347
6348
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006349RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006350 NoHandleAllocation ha;
6351 ASSERT(args.length() == 2);
6352
6353 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6354 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006355 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006356}
6357
6358
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006359RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006360 NoHandleAllocation ha;
6361 ASSERT(args.length() == 1);
6362
6363 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006364 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006365}
6366
6367
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006368RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006369 NoHandleAllocation ha;
6370 ASSERT(args.length() == 2);
6371
6372 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6373 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006374 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006375}
6376
6377
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006378RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006379 NoHandleAllocation ha;
6380 ASSERT(args.length() == 2);
6381
6382 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6383 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006384 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006385}
6386
6387
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006388RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006389 NoHandleAllocation ha;
6390 ASSERT(args.length() == 2);
6391
6392 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6393 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006394 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006395}
6396
6397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006398RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006399 NoHandleAllocation ha;
6400 ASSERT(args.length() == 2);
6401
6402 CONVERT_DOUBLE_CHECKED(x, args[0]);
6403 CONVERT_DOUBLE_CHECKED(y, args[1]);
6404 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6405 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6406 if (x == y) return Smi::FromInt(EQUAL);
6407 Object* result;
6408 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6409 result = Smi::FromInt(EQUAL);
6410 } else {
6411 result = Smi::FromInt(NOT_EQUAL);
6412 }
6413 return result;
6414}
6415
6416
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006417RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006418 NoHandleAllocation ha;
6419 ASSERT(args.length() == 2);
6420
6421 CONVERT_CHECKED(String, x, args[0]);
6422 CONVERT_CHECKED(String, y, args[1]);
6423
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006424 bool not_equal = !x->Equals(y);
6425 // This is slightly convoluted because the value that signifies
6426 // equality is 0 and inequality is 1 so we have to negate the result
6427 // from String::Equals.
6428 ASSERT(not_equal == 0 || not_equal == 1);
6429 STATIC_CHECK(EQUAL == 0);
6430 STATIC_CHECK(NOT_EQUAL == 1);
6431 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006432}
6433
6434
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006435RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006436 NoHandleAllocation ha;
6437 ASSERT(args.length() == 3);
6438
6439 CONVERT_DOUBLE_CHECKED(x, args[0]);
6440 CONVERT_DOUBLE_CHECKED(y, args[1]);
6441 if (isnan(x) || isnan(y)) return args[2];
6442 if (x == y) return Smi::FromInt(EQUAL);
6443 if (isless(x, y)) return Smi::FromInt(LESS);
6444 return Smi::FromInt(GREATER);
6445}
6446
6447
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006448// Compare two Smis as if they were converted to strings and then
6449// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006450RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006451 NoHandleAllocation ha;
6452 ASSERT(args.length() == 2);
6453
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006454 // Extract the integer values from the Smis.
6455 CONVERT_CHECKED(Smi, x, args[0]);
6456 CONVERT_CHECKED(Smi, y, args[1]);
6457 int x_value = x->value();
6458 int y_value = y->value();
6459
6460 // If the integers are equal so are the string representations.
6461 if (x_value == y_value) return Smi::FromInt(EQUAL);
6462
6463 // If one of the integers are zero the normal integer order is the
6464 // same as the lexicographic order of the string representations.
6465 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6466
ager@chromium.org32912102009-01-16 10:38:43 +00006467 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006468 // smallest because the char code of '-' is less than the char code
6469 // of any digit. Otherwise, we make both values positive.
6470 if (x_value < 0 || y_value < 0) {
6471 if (y_value >= 0) return Smi::FromInt(LESS);
6472 if (x_value >= 0) return Smi::FromInt(GREATER);
6473 x_value = -x_value;
6474 y_value = -y_value;
6475 }
6476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006477 // Arrays for the individual characters of the two Smis. Smis are
6478 // 31 bit integers and 10 decimal digits are therefore enough.
6479 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6480 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6481 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6482
6483
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006484 // Convert the integers to arrays of their decimal digits.
6485 int x_index = 0;
6486 int y_index = 0;
6487 while (x_value > 0) {
6488 x_elms[x_index++] = x_value % 10;
6489 x_value /= 10;
6490 }
6491 while (y_value > 0) {
6492 y_elms[y_index++] = y_value % 10;
6493 y_value /= 10;
6494 }
6495
6496 // Loop through the arrays of decimal digits finding the first place
6497 // where they differ.
6498 while (--x_index >= 0 && --y_index >= 0) {
6499 int diff = x_elms[x_index] - y_elms[y_index];
6500 if (diff != 0) return Smi::FromInt(diff);
6501 }
6502
6503 // If one array is a suffix of the other array, the longest array is
6504 // the representation of the largest of the Smis in the
6505 // lexicographic ordering.
6506 return Smi::FromInt(x_index - y_index);
6507}
6508
6509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006510static Object* StringInputBufferCompare(RuntimeState* state,
6511 String* x,
6512 String* y) {
6513 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6514 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006515 bufx.Reset(x);
6516 bufy.Reset(y);
6517 while (bufx.has_more() && bufy.has_more()) {
6518 int d = bufx.GetNext() - bufy.GetNext();
6519 if (d < 0) return Smi::FromInt(LESS);
6520 else if (d > 0) return Smi::FromInt(GREATER);
6521 }
6522
6523 // x is (non-trivial) prefix of y:
6524 if (bufy.has_more()) return Smi::FromInt(LESS);
6525 // y is prefix of x:
6526 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6527}
6528
6529
6530static Object* FlatStringCompare(String* x, String* y) {
6531 ASSERT(x->IsFlat());
6532 ASSERT(y->IsFlat());
6533 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6534 int prefix_length = x->length();
6535 if (y->length() < prefix_length) {
6536 prefix_length = y->length();
6537 equal_prefix_result = Smi::FromInt(GREATER);
6538 } else if (y->length() > prefix_length) {
6539 equal_prefix_result = Smi::FromInt(LESS);
6540 }
6541 int r;
6542 if (x->IsAsciiRepresentation()) {
6543 Vector<const char> x_chars = x->ToAsciiVector();
6544 if (y->IsAsciiRepresentation()) {
6545 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006546 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006547 } else {
6548 Vector<const uc16> y_chars = y->ToUC16Vector();
6549 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6550 }
6551 } else {
6552 Vector<const uc16> x_chars = x->ToUC16Vector();
6553 if (y->IsAsciiRepresentation()) {
6554 Vector<const char> y_chars = y->ToAsciiVector();
6555 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6556 } else {
6557 Vector<const uc16> y_chars = y->ToUC16Vector();
6558 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6559 }
6560 }
6561 Object* result;
6562 if (r == 0) {
6563 result = equal_prefix_result;
6564 } else {
6565 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6566 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006567 ASSERT(result ==
6568 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006569 return result;
6570}
6571
6572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006573RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006574 NoHandleAllocation ha;
6575 ASSERT(args.length() == 2);
6576
6577 CONVERT_CHECKED(String, x, args[0]);
6578 CONVERT_CHECKED(String, y, args[1]);
6579
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006580 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006581
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582 // A few fast case tests before we flatten.
6583 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006584 if (y->length() == 0) {
6585 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006586 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006587 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006588 return Smi::FromInt(LESS);
6589 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006590
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006591 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006592 if (d < 0) return Smi::FromInt(LESS);
6593 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006594
lrn@chromium.org303ada72010-10-27 09:33:13 +00006595 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006596 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006597 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6598 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006599 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006600 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6601 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006602
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006603 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006604 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006605}
6606
6607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006608RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006609 NoHandleAllocation ha;
6610 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006611 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006612
6613 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006614 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006615}
6616
6617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006618RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619 NoHandleAllocation ha;
6620 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006621 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006622
6623 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006624 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006625}
6626
6627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006628RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 NoHandleAllocation ha;
6630 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006631 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006632
6633 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006634 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006635}
6636
6637
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006638static const double kPiDividedBy4 = 0.78539816339744830962;
6639
6640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006641RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006642 NoHandleAllocation ha;
6643 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006644 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006645
6646 CONVERT_DOUBLE_CHECKED(x, args[0]);
6647 CONVERT_DOUBLE_CHECKED(y, args[1]);
6648 double result;
6649 if (isinf(x) && isinf(y)) {
6650 // Make sure that the result in case of two infinite arguments
6651 // is a multiple of Pi / 4. The sign of the result is determined
6652 // by the first argument (x) and the sign of the second argument
6653 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006654 int multiplier = (x < 0) ? -1 : 1;
6655 if (y < 0) multiplier *= 3;
6656 result = multiplier * kPiDividedBy4;
6657 } else {
6658 result = atan2(x, y);
6659 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006660 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006661}
6662
6663
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006664RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006665 NoHandleAllocation ha;
6666 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006667 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006668
6669 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006670 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006671}
6672
6673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006674RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006675 NoHandleAllocation ha;
6676 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006677 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006678
6679 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006680 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006681}
6682
6683
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006684RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006685 NoHandleAllocation ha;
6686 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006687 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006688
6689 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006690 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006691}
6692
6693
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006694RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006695 NoHandleAllocation ha;
6696 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006697 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006698
6699 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006700 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006701}
6702
6703
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006704RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006705 NoHandleAllocation ha;
6706 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006707 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006708
6709 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006710 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006711}
6712
6713
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006714RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006715 NoHandleAllocation ha;
6716 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006717 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006718
6719 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006720
6721 // If the second argument is a smi, it is much faster to call the
6722 // custom powi() function than the generic pow().
6723 if (args[1]->IsSmi()) {
6724 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006725 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006726 }
6727
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006728 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006729 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006730}
6731
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006732// Fast version of Math.pow if we know that y is not an integer and
6733// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006734RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006735 NoHandleAllocation ha;
6736 ASSERT(args.length() == 2);
6737 CONVERT_DOUBLE_CHECKED(x, args[0]);
6738 CONVERT_DOUBLE_CHECKED(y, args[1]);
6739 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006740 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006741 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006742 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006743 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006745 }
6746}
6747
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006748
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006749RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006750 NoHandleAllocation ha;
6751 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006752 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006754 if (!args[0]->IsHeapNumber()) {
6755 // Must be smi. Return the argument unchanged for all the other types
6756 // to make fuzz-natives test happy.
6757 return args[0];
6758 }
6759
6760 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6761
6762 double value = number->value();
6763 int exponent = number->get_exponent();
6764 int sign = number->get_sign();
6765
danno@chromium.org160a7b02011-04-18 15:51:38 +00006766 if (exponent < -1) {
6767 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6768 if (sign) return isolate->heap()->minus_zero_value();
6769 return Smi::FromInt(0);
6770 }
6771
6772 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6773 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6774 // agument holds for 32-bit smis).
6775 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006776 return Smi::FromInt(static_cast<int>(value + 0.5));
6777 }
6778
6779 // If the magnitude is big enough, there's no place for fraction part. If we
6780 // try to add 0.5 to this number, 1.0 will be added instead.
6781 if (exponent >= 52) {
6782 return number;
6783 }
6784
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006785 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006786
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006787 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006788 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006789}
6790
6791
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006792RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006793 NoHandleAllocation ha;
6794 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006795 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796
6797 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006798 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006799}
6800
6801
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006802RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006803 NoHandleAllocation ha;
6804 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006805 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006806
6807 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006808 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006809}
6810
6811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006812RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006813 NoHandleAllocation ha;
6814 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006815 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006816
6817 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006818 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006819}
6820
6821
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006822static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006823 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6824 181, 212, 243, 273, 304, 334};
6825 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6826 182, 213, 244, 274, 305, 335};
6827
6828 year += month / 12;
6829 month %= 12;
6830 if (month < 0) {
6831 year--;
6832 month += 12;
6833 }
6834
6835 ASSERT(month >= 0);
6836 ASSERT(month < 12);
6837
6838 // year_delta is an arbitrary number such that:
6839 // a) year_delta = -1 (mod 400)
6840 // b) year + year_delta > 0 for years in the range defined by
6841 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6842 // Jan 1 1970. This is required so that we don't run into integer
6843 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006844 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006845 // operations.
6846 static const int year_delta = 399999;
6847 static const int base_day = 365 * (1970 + year_delta) +
6848 (1970 + year_delta) / 4 -
6849 (1970 + year_delta) / 100 +
6850 (1970 + year_delta) / 400;
6851
6852 int year1 = year + year_delta;
6853 int day_from_year = 365 * year1 +
6854 year1 / 4 -
6855 year1 / 100 +
6856 year1 / 400 -
6857 base_day;
6858
6859 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006860 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006861 }
6862
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006863 return day_from_year + day_from_month_leap[month] + day - 1;
6864}
6865
6866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006867RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006868 NoHandleAllocation ha;
6869 ASSERT(args.length() == 3);
6870
6871 CONVERT_SMI_CHECKED(year, args[0]);
6872 CONVERT_SMI_CHECKED(month, args[1]);
6873 CONVERT_SMI_CHECKED(date, args[2]);
6874
6875 return Smi::FromInt(MakeDay(year, month, date));
6876}
6877
6878
6879static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6880static const int kDaysIn4Years = 4 * 365 + 1;
6881static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6882static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6883static const int kDays1970to2000 = 30 * 365 + 7;
6884static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6885 kDays1970to2000;
6886static const int kYearsOffset = 400000;
6887
6888static const char kDayInYear[] = {
6889 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6890 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6891 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6892 22, 23, 24, 25, 26, 27, 28,
6893 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6894 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6895 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6896 22, 23, 24, 25, 26, 27, 28, 29, 30,
6897 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6898 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6899 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6900 22, 23, 24, 25, 26, 27, 28, 29, 30,
6901 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6902 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6903 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6904 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6905 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6906 22, 23, 24, 25, 26, 27, 28, 29, 30,
6907 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6908 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6909 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6910 22, 23, 24, 25, 26, 27, 28, 29, 30,
6911 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6912 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6913
6914 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6915 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6916 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6917 22, 23, 24, 25, 26, 27, 28,
6918 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6919 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6920 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6921 22, 23, 24, 25, 26, 27, 28, 29, 30,
6922 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6923 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6924 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6925 22, 23, 24, 25, 26, 27, 28, 29, 30,
6926 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6927 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6928 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6929 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6930 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6931 22, 23, 24, 25, 26, 27, 28, 29, 30,
6932 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6933 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6934 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6935 22, 23, 24, 25, 26, 27, 28, 29, 30,
6936 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6937 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6938
6939 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6940 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6941 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6942 22, 23, 24, 25, 26, 27, 28, 29,
6943 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6944 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6945 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6946 22, 23, 24, 25, 26, 27, 28, 29, 30,
6947 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6948 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6949 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6950 22, 23, 24, 25, 26, 27, 28, 29, 30,
6951 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6952 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6953 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6954 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6955 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6956 22, 23, 24, 25, 26, 27, 28, 29, 30,
6957 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6958 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6959 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6960 22, 23, 24, 25, 26, 27, 28, 29, 30,
6961 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6962 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6963
6964 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6965 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6966 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6967 22, 23, 24, 25, 26, 27, 28,
6968 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6969 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6970 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6971 22, 23, 24, 25, 26, 27, 28, 29, 30,
6972 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6973 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6974 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6975 22, 23, 24, 25, 26, 27, 28, 29, 30,
6976 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6977 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6978 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6979 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6980 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6981 22, 23, 24, 25, 26, 27, 28, 29, 30,
6982 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6983 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6984 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6985 22, 23, 24, 25, 26, 27, 28, 29, 30,
6986 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6987 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6988
6989static const char kMonthInYear[] = {
6990 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,
6991 0, 0, 0, 0, 0, 0,
6992 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,
6993 1, 1, 1,
6994 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,
6995 2, 2, 2, 2, 2, 2,
6996 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,
6997 3, 3, 3, 3, 3,
6998 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,
6999 4, 4, 4, 4, 4, 4,
7000 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,
7001 5, 5, 5, 5, 5,
7002 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,
7003 6, 6, 6, 6, 6, 6,
7004 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,
7005 7, 7, 7, 7, 7, 7,
7006 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,
7007 8, 8, 8, 8, 8,
7008 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,
7009 9, 9, 9, 9, 9, 9,
7010 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7011 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7012 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7013 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7014
7015 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,
7016 0, 0, 0, 0, 0, 0,
7017 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,
7018 1, 1, 1,
7019 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,
7020 2, 2, 2, 2, 2, 2,
7021 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,
7022 3, 3, 3, 3, 3,
7023 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,
7024 4, 4, 4, 4, 4, 4,
7025 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,
7026 5, 5, 5, 5, 5,
7027 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,
7028 6, 6, 6, 6, 6, 6,
7029 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,
7030 7, 7, 7, 7, 7, 7,
7031 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,
7032 8, 8, 8, 8, 8,
7033 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,
7034 9, 9, 9, 9, 9, 9,
7035 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7036 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7037 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7038 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7039
7040 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,
7041 0, 0, 0, 0, 0, 0,
7042 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,
7043 1, 1, 1, 1,
7044 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,
7045 2, 2, 2, 2, 2, 2,
7046 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,
7047 3, 3, 3, 3, 3,
7048 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,
7049 4, 4, 4, 4, 4, 4,
7050 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,
7051 5, 5, 5, 5, 5,
7052 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,
7053 6, 6, 6, 6, 6, 6,
7054 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,
7055 7, 7, 7, 7, 7, 7,
7056 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,
7057 8, 8, 8, 8, 8,
7058 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,
7059 9, 9, 9, 9, 9, 9,
7060 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7061 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7062 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7063 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7064
7065 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,
7066 0, 0, 0, 0, 0, 0,
7067 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,
7068 1, 1, 1,
7069 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,
7070 2, 2, 2, 2, 2, 2,
7071 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,
7072 3, 3, 3, 3, 3,
7073 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,
7074 4, 4, 4, 4, 4, 4,
7075 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,
7076 5, 5, 5, 5, 5,
7077 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,
7078 6, 6, 6, 6, 6, 6,
7079 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,
7080 7, 7, 7, 7, 7, 7,
7081 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,
7082 8, 8, 8, 8, 8,
7083 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,
7084 9, 9, 9, 9, 9, 9,
7085 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7086 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7087 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7088 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7089
7090
7091// This function works for dates from 1970 to 2099.
7092static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007093 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007094#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007095 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007096#endif
7097
7098 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7099 date %= kDaysIn4Years;
7100
7101 month = kMonthInYear[date];
7102 day = kDayInYear[date];
7103
7104 ASSERT(MakeDay(year, month, day) == save_date);
7105}
7106
7107
7108static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007109 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007110#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007111 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007112#endif
7113
7114 date += kDaysOffset;
7115 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7116 date %= kDaysIn400Years;
7117
7118 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7119
7120 date--;
7121 int yd1 = date / kDaysIn100Years;
7122 date %= kDaysIn100Years;
7123 year += 100 * yd1;
7124
7125 date++;
7126 int yd2 = date / kDaysIn4Years;
7127 date %= kDaysIn4Years;
7128 year += 4 * yd2;
7129
7130 date--;
7131 int yd3 = date / 365;
7132 date %= 365;
7133 year += yd3;
7134
7135 bool is_leap = (!yd1 || yd2) && !yd3;
7136
7137 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007138 ASSERT(is_leap || (date >= 0));
7139 ASSERT((date < 365) || (is_leap && (date < 366)));
7140 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7141 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7142 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007143
7144 if (is_leap) {
7145 day = kDayInYear[2*365 + 1 + date];
7146 month = kMonthInYear[2*365 + 1 + date];
7147 } else {
7148 day = kDayInYear[date];
7149 month = kMonthInYear[date];
7150 }
7151
7152 ASSERT(MakeDay(year, month, day) == save_date);
7153}
7154
7155
7156static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007157 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007158 if (date >= 0 && date < 32 * kDaysIn4Years) {
7159 DateYMDFromTimeAfter1970(date, year, month, day);
7160 } else {
7161 DateYMDFromTimeSlow(date, year, month, day);
7162 }
7163}
7164
7165
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007166RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007167 NoHandleAllocation ha;
7168 ASSERT(args.length() == 2);
7169
7170 CONVERT_DOUBLE_CHECKED(t, args[0]);
7171 CONVERT_CHECKED(JSArray, res_array, args[1]);
7172
7173 int year, month, day;
7174 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7175
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007176 RUNTIME_ASSERT(res_array->elements()->map() ==
7177 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007178 FixedArray* elms = FixedArray::cast(res_array->elements());
7179 RUNTIME_ASSERT(elms->length() == 3);
7180
7181 elms->set(0, Smi::FromInt(year));
7182 elms->set(1, Smi::FromInt(month));
7183 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007184
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007185 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007186}
7187
7188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007189RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007190 NoHandleAllocation ha;
7191 ASSERT(args.length() == 3);
7192
7193 JSFunction* callee = JSFunction::cast(args[0]);
7194 Object** parameters = reinterpret_cast<Object**>(args[1]);
7195 const int length = Smi::cast(args[2])->value();
7196
lrn@chromium.org303ada72010-10-27 09:33:13 +00007197 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007198 { MaybeObject* maybe_result =
7199 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007200 if (!maybe_result->ToObject(&result)) return maybe_result;
7201 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007202 // Allocate the elements if needed.
7203 if (length > 0) {
7204 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007205 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007206 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007207 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7208 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007209
7210 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007211 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007212 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007213 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007214
7215 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007216 for (int i = 0; i < length; i++) {
7217 array->set(i, *--parameters, mode);
7218 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007219 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007220 }
7221 return result;
7222}
7223
7224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007225RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007226 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007227 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007228 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007229 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007230 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007231
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007232 // Allocate global closures in old space and allocate local closures
7233 // in new space. Additionally pretenure closures that are assigned
7234 // directly to properties.
7235 pretenure = pretenure || (context->global_context() == *context);
7236 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007237 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007238 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7239 context,
7240 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007241 return *result;
7242}
7243
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007244
7245static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7246 int* total_argc) {
7247 // Find frame containing arguments passed to the caller.
7248 JavaScriptFrameIterator it;
7249 JavaScriptFrame* frame = it.frame();
7250 List<JSFunction*> functions(2);
7251 frame->GetFunctions(&functions);
7252 if (functions.length() > 1) {
7253 int inlined_frame_index = functions.length() - 1;
7254 JSFunction* inlined_function = functions[inlined_frame_index];
7255 int args_count = inlined_function->shared()->formal_parameter_count();
7256 ScopedVector<SlotRef> args_slots(args_count);
7257 SlotRef::ComputeSlotMappingForArguments(frame,
7258 inlined_frame_index,
7259 &args_slots);
7260
7261 *total_argc = bound_argc + args_count;
7262 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7263 for (int i = 0; i < args_count; i++) {
7264 Handle<Object> val = args_slots[i].GetValue();
7265 param_data[bound_argc + i] = val.location();
7266 }
7267 return param_data;
7268 } else {
7269 it.AdvanceToArgumentsFrame();
7270 frame = it.frame();
7271 int args_count = frame->ComputeParametersCount();
7272
7273 *total_argc = bound_argc + args_count;
7274 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7275 for (int i = 0; i < args_count; i++) {
7276 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7277 param_data[bound_argc + i] = val.location();
7278 }
7279 return param_data;
7280 }
7281}
7282
7283
7284RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007285 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007286 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007287 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007288 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007289
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007290 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007291 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007292 int bound_argc = 0;
7293 if (!args[1]->IsNull()) {
7294 CONVERT_ARG_CHECKED(JSArray, params, 1);
7295 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007296 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007297 bound_argc = Smi::cast(params->length())->value();
7298 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007299
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007300 int total_argc = 0;
7301 SmartPointer<Object**> param_data =
7302 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007303 for (int i = 0; i < bound_argc; i++) {
7304 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007305 param_data[i] = val.location();
7306 }
7307
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007308 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007309 Handle<Object> result =
7310 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007311 if (exception) {
7312 return Failure::Exception();
7313 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007314
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007315 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007316 return *result;
7317}
7318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007319
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007320static void TrySettingInlineConstructStub(Isolate* isolate,
7321 Handle<JSFunction> function) {
7322 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007323 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007324 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007325 }
7326 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007327 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007328 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007329 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007330 function->shared()->set_construct_stub(
7331 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007332 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007333 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007334}
7335
7336
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007337RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007338 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007339 ASSERT(args.length() == 1);
7340
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007341 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007342
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007343 // If the constructor isn't a proper function we throw a type error.
7344 if (!constructor->IsJSFunction()) {
7345 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7346 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007347 isolate->factory()->NewTypeError("not_constructor", arguments);
7348 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007349 }
7350
7351 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007352
7353 // If function should not have prototype, construction is not allowed. In this
7354 // case generated code bailouts here, since function has no initial_map.
7355 if (!function->should_have_prototype()) {
7356 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7357 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007358 isolate->factory()->NewTypeError("not_constructor", arguments);
7359 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007360 }
7361
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007362#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007363 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007364 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007365 if (debug->StepInActive()) {
7366 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007367 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007368#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007369
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007370 if (function->has_initial_map()) {
7371 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007372 // The 'Function' function ignores the receiver object when
7373 // called using 'new' and creates a new JSFunction object that
7374 // is returned. The receiver object is only used for error
7375 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007376 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007377 // allocate JSFunctions since it does not properly initialize
7378 // the shared part of the function. Since the receiver is
7379 // ignored anyway, we use the global object as the receiver
7380 // instead of a new JSFunction object. This way, errors are
7381 // reported the same way whether or not 'Function' is called
7382 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007383 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007385 }
7386
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007387 // The function should be compiled for the optimization hints to be
7388 // available. We cannot use EnsureCompiled because that forces a
7389 // compilation through the shared function info which makes it
7390 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007391 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007392 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007393
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007394 if (!function->has_initial_map() &&
7395 shared->IsInobjectSlackTrackingInProgress()) {
7396 // The tracking is already in progress for another function. We can only
7397 // track one initial_map at a time, so we force the completion before the
7398 // function is called as a constructor for the first time.
7399 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007400 }
7401
7402 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007403 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7404 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007405 // Delay setting the stub if inobject slack tracking is in progress.
7406 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007407 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007408 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007409
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007410 isolate->counters()->constructed_objects()->Increment();
7411 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007412
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007413 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007414}
7415
7416
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007417RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007418 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007419 ASSERT(args.length() == 1);
7420
7421 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7422 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007423 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007424
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007425 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007426}
7427
7428
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007429RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007430 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007431 ASSERT(args.length() == 1);
7432
7433 Handle<JSFunction> function = args.at<JSFunction>(0);
7434#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007435 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007436 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007437 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007438 PrintF("]\n");
7439 }
7440#endif
7441
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007442 // Compile the target function. Here we compile using CompileLazyInLoop in
7443 // order to get the optimized version. This helps code like delta-blue
7444 // that calls performance-critical routines through constructors. A
7445 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7446 // direct call. Since the in-loop tracking takes place through CallICs
7447 // this means that things called through constructors are never known to
7448 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007449 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007450 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007451 return Failure::Exception();
7452 }
7453
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007454 // All done. Return the compiled code.
7455 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007456 return function->code();
7457}
7458
7459
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007460RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007461 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007462 ASSERT(args.length() == 1);
7463 Handle<JSFunction> function = args.at<JSFunction>(0);
7464 // If the function is not optimizable or debugger is active continue using the
7465 // code from the full compiler.
7466 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007467 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007468 if (FLAG_trace_opt) {
7469 PrintF("[failed to optimize ");
7470 function->PrintName();
7471 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7472 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007473 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007474 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007475 function->ReplaceCode(function->shared()->code());
7476 return function->code();
7477 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007478 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007479 return function->code();
7480 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007481 if (FLAG_trace_opt) {
7482 PrintF("[failed to optimize ");
7483 function->PrintName();
7484 PrintF(": optimized compilation failed]\n");
7485 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007486 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007487 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007488}
7489
7490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007491RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007492 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007493 ASSERT(args.length() == 1);
7494 RUNTIME_ASSERT(args[0]->IsSmi());
7495 Deoptimizer::BailoutType type =
7496 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007497 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7498 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007499 int frames = deoptimizer->output_count();
7500
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007501 deoptimizer->MaterializeHeapNumbers();
7502 delete deoptimizer;
7503
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007504 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007505 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007506 for (int i = 0; i < frames - 1; i++) it.Advance();
7507 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007508
7509 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007510 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007511 Handle<Object> arguments;
7512 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007513 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007514 if (arguments.is_null()) {
7515 // FunctionGetArguments can't throw an exception, so cast away the
7516 // doubt with an assert.
7517 arguments = Handle<Object>(
7518 Accessors::FunctionGetArguments(*function,
7519 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007520 ASSERT(*arguments != isolate->heap()->null_value());
7521 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007522 }
7523 frame->SetExpression(i, *arguments);
7524 }
7525 }
7526
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007527 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007528 if (type == Deoptimizer::EAGER) {
7529 RUNTIME_ASSERT(function->IsOptimized());
7530 } else {
7531 RUNTIME_ASSERT(!function->IsOptimized());
7532 }
7533
7534 // Avoid doing too much work when running with --always-opt and keep
7535 // the optimized code around.
7536 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007537 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007538 }
7539
7540 // Count the number of optimized activations of the function.
7541 int activations = 0;
7542 while (!it.done()) {
7543 JavaScriptFrame* frame = it.frame();
7544 if (frame->is_optimized() && frame->function() == *function) {
7545 activations++;
7546 }
7547 it.Advance();
7548 }
7549
7550 // TODO(kasperl): For now, we cannot support removing the optimized
7551 // code when we have recursive invocations of the same function.
7552 if (activations == 0) {
7553 if (FLAG_trace_deopt) {
7554 PrintF("[removing optimized code for: ");
7555 function->PrintName();
7556 PrintF("]\n");
7557 }
7558 function->ReplaceCode(function->shared()->code());
7559 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007560 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007561}
7562
7563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007564RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007565 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007566 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007567 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007568}
7569
7570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007571RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007572 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007573 ASSERT(args.length() == 1);
7574 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007575 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007576
7577 Deoptimizer::DeoptimizeFunction(*function);
7578
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007579 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007580}
7581
7582
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007583RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7584 HandleScope scope(isolate);
7585 ASSERT(args.length() == 1);
7586 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7587 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7588 function->MarkForLazyRecompilation();
7589 return isolate->heap()->undefined_value();
7590}
7591
7592
lrn@chromium.org1c092762011-05-09 09:42:16 +00007593RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7594 HandleScope scope(isolate);
7595 ASSERT(args.length() == 1);
7596 if (!V8::UseCrankshaft()) {
7597 return Smi::FromInt(4); // 4 == "never".
7598 }
7599 if (FLAG_always_opt) {
7600 return Smi::FromInt(3); // 3 == "always".
7601 }
7602 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7603 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7604 : Smi::FromInt(2); // 2 == "no".
7605}
7606
7607
7608RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7609 HandleScope scope(isolate);
7610 ASSERT(args.length() == 1);
7611 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7612 return Smi::FromInt(function->shared()->opt_count());
7613}
7614
7615
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007616RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007617 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007618 ASSERT(args.length() == 1);
7619 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7620
7621 // We're not prepared to handle a function with arguments object.
7622 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7623
7624 // We have hit a back edge in an unoptimized frame for a function that was
7625 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007626 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007627 // Keep track of whether we've succeeded in optimizing.
7628 bool succeeded = unoptimized->optimizable();
7629 if (succeeded) {
7630 // If we are trying to do OSR when there are already optimized
7631 // activations of the function, it means (a) the function is directly or
7632 // indirectly recursive and (b) an optimized invocation has been
7633 // deoptimized so that we are currently in an unoptimized activation.
7634 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007635 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007636 while (succeeded && !it.done()) {
7637 JavaScriptFrame* frame = it.frame();
7638 succeeded = !frame->is_optimized() || frame->function() != *function;
7639 it.Advance();
7640 }
7641 }
7642
7643 int ast_id = AstNode::kNoNumber;
7644 if (succeeded) {
7645 // The top JS function is this one, the PC is somewhere in the
7646 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007647 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007648 JavaScriptFrame* frame = it.frame();
7649 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007650 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007651 ASSERT(unoptimized->contains(frame->pc()));
7652
7653 // Use linear search of the unoptimized code's stack check table to find
7654 // the AST id matching the PC.
7655 Address start = unoptimized->instruction_start();
7656 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007657 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007658 uint32_t table_length = Memory::uint32_at(table_cursor);
7659 table_cursor += kIntSize;
7660 for (unsigned i = 0; i < table_length; ++i) {
7661 // Table entries are (AST id, pc offset) pairs.
7662 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7663 if (pc_offset == target_pc_offset) {
7664 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7665 break;
7666 }
7667 table_cursor += 2 * kIntSize;
7668 }
7669 ASSERT(ast_id != AstNode::kNoNumber);
7670 if (FLAG_trace_osr) {
7671 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7672 function->PrintName();
7673 PrintF("]\n");
7674 }
7675
7676 // Try to compile the optimized code. A true return value from
7677 // CompileOptimized means that compilation succeeded, not necessarily
7678 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007679 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7680 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007681 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7682 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007683 if (data->OsrPcOffset()->value() >= 0) {
7684 if (FLAG_trace_osr) {
7685 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007686 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007687 }
7688 ASSERT(data->OsrAstId()->value() == ast_id);
7689 } else {
7690 // We may never generate the desired OSR entry if we emit an
7691 // early deoptimize.
7692 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007693 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007694 } else {
7695 succeeded = false;
7696 }
7697 }
7698
7699 // Revert to the original stack checks in the original unoptimized code.
7700 if (FLAG_trace_osr) {
7701 PrintF("[restoring original stack checks in ");
7702 function->PrintName();
7703 PrintF("]\n");
7704 }
7705 StackCheckStub check_stub;
7706 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007707 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007708 Deoptimizer::RevertStackCheckCode(*unoptimized,
7709 *check_code,
7710 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007711
7712 // Allow OSR only at nesting level zero again.
7713 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7714
7715 // If the optimization attempt succeeded, return the AST id tagged as a
7716 // smi. This tells the builtin that we need to translate the unoptimized
7717 // frame to an optimized one.
7718 if (succeeded) {
7719 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7720 return Smi::FromInt(ast_id);
7721 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007722 if (function->IsMarkedForLazyRecompilation()) {
7723 function->ReplaceCode(function->shared()->code());
7724 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007725 return Smi::FromInt(-1);
7726 }
7727}
7728
7729
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007730RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007731 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007732 ASSERT(args.length() == 1);
7733 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7734 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7735}
7736
7737
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007738RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007739 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007740 ASSERT(args.length() == 1);
7741 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7742 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7743}
7744
7745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007746RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007747 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007748 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007749
kasper.lund7276f142008-07-30 08:49:36 +00007750 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007751 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007752 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007753 { MaybeObject* maybe_result =
7754 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007755 if (!maybe_result->ToObject(&result)) return maybe_result;
7756 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007757
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007758 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007759
kasper.lund7276f142008-07-30 08:49:36 +00007760 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007761}
7762
lrn@chromium.org303ada72010-10-27 09:33:13 +00007763
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007764MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7765 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007766 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007767 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007768 Object* js_object = object;
7769 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007770 MaybeObject* maybe_js_object = js_object->ToObject();
7771 if (!maybe_js_object->ToObject(&js_object)) {
7772 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7773 return maybe_js_object;
7774 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007775 HandleScope scope(isolate);
7776 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007777 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007778 isolate->factory()->NewTypeError("with_expression",
7779 HandleVector(&handle, 1));
7780 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007781 }
7782 }
7783
lrn@chromium.org303ada72010-10-27 09:33:13 +00007784 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007785 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7786 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007787 if (!maybe_result->ToObject(&result)) return maybe_result;
7788 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007789
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007790 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007791 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007792
kasper.lund7276f142008-07-30 08:49:36 +00007793 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007794}
7795
7796
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007797RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007798 NoHandleAllocation ha;
7799 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007800 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007801}
7802
7803
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007804RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007805 NoHandleAllocation ha;
7806 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007807 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007808}
7809
7810
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007811RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007812 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007813 ASSERT(args.length() == 2);
7814
7815 CONVERT_ARG_CHECKED(Context, context, 0);
7816 CONVERT_ARG_CHECKED(String, name, 1);
7817
7818 int index;
7819 PropertyAttributes attributes;
7820 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007821 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007822
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007823 // If the slot was not found the result is true.
7824 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007825 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007826 }
7827
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007828 // If the slot was found in a context, it should be DONT_DELETE.
7829 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007830 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007831 }
7832
7833 // The slot was found in a JSObject, either a context extension object,
7834 // the global object, or an arguments object. Try to delete it
7835 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7836 // which allows deleting all parameters in functions that mention
7837 // 'arguments', we do this even for the case of slots found on an
7838 // arguments object. The slot was found on an arguments object if the
7839 // index is non-negative.
7840 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7841 if (index >= 0) {
7842 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7843 } else {
7844 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7845 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007846}
7847
7848
ager@chromium.orga1645e22009-09-09 19:27:10 +00007849// A mechanism to return a pair of Object pointers in registers (if possible).
7850// How this is achieved is calling convention-dependent.
7851// All currently supported x86 compiles uses calling conventions that are cdecl
7852// variants where a 64-bit value is returned in two 32-bit registers
7853// (edx:eax on ia32, r1:r0 on ARM).
7854// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7855// In Win64 calling convention, a struct of two pointers is returned in memory,
7856// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007857#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007858struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007859 MaybeObject* x;
7860 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007861};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007862
lrn@chromium.org303ada72010-10-27 09:33:13 +00007863static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007864 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007865 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7866 // In Win64 they are assigned to a hidden first argument.
7867 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007868}
7869#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007870typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007871static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007872 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007873 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007874}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007875#endif
7876
7877
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007878static inline MaybeObject* Unhole(Heap* heap,
7879 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007880 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007881 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7882 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007883 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007884}
7885
7886
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007887static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate,
7888 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007889 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007890 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007891 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007892 JSFunction* context_extension_function =
7893 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007894 // If the holder isn't a context extension object, we just return it
7895 // as the receiver. This allows arguments objects to be used as
7896 // receivers, but only if they are put in the context scope chain
7897 // explicitly via a with-statement.
7898 Object* constructor = holder->map()->constructor();
7899 if (constructor != context_extension_function) return holder;
7900 // Fall back to using the global object as the receiver if the
7901 // property turns out to be a local variable allocated in a context
7902 // extension object - introduced via eval.
7903 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007904}
7905
7906
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007907static ObjectPair LoadContextSlotHelper(Arguments args,
7908 Isolate* isolate,
7909 bool throw_error) {
7910 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00007911 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007912
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007913 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007914 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007915 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007916 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007917 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007918
7919 int index;
7920 PropertyAttributes attributes;
7921 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007922 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007923
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007924 // If the index is non-negative, the slot has been found in a local
7925 // variable or a parameter. Read it from the context object or the
7926 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007927 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007928 // If the "property" we were looking for is a local variable or an
7929 // argument in a context, the receiver is the global object; see
7930 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007931 // GetElement below can cause GC.
7932 Handle<JSObject> receiver(
7933 isolate->context()->global()->global_receiver());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007934 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007935 ? Context::cast(*holder)->get(index)
7936 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007937 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007938 }
7939
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007940 // If the holder is found, we read the property from it.
7941 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007942 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007943 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007944 JSObject* receiver;
7945 if (object->IsGlobalObject()) {
7946 receiver = GlobalObject::cast(object)->global_receiver();
7947 } else if (context->is_exception_holder(*holder)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007948 receiver = isolate->context()->global()->global_receiver();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007949 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007950 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007951 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007952
7953 // GetProperty below can cause GC.
7954 Handle<JSObject> receiver_handle(receiver);
7955
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007956 // No need to unhole the value here. This is taken care of by the
7957 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007958 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007959 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007960 }
7961
7962 if (throw_error) {
7963 // The property doesn't exist - throw exception.
7964 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007965 isolate->factory()->NewReferenceError("not_defined",
7966 HandleVector(&name, 1));
7967 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007968 } else {
7969 // The property doesn't exist - return undefined
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007970 return MakePair(isolate->heap()->undefined_value(),
7971 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007972 }
7973}
7974
7975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007976RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007977 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007978}
7979
7980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007981RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007982 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007983}
7984
7985
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007986RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007987 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007988 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007989
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007990 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007991 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007992 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007993 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7994 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7995 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007996 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007997
7998 int index;
7999 PropertyAttributes attributes;
8000 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008001 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008002
8003 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008004 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008005 // Ignore if read_only variable.
8006 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008007 // Context is a fixed array and set cannot fail.
8008 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008009 } else if (strict_mode == kStrictMode) {
8010 // Setting read only property in strict mode.
8011 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008012 isolate->factory()->NewTypeError("strict_cannot_assign",
8013 HandleVector(&name, 1));
8014 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008015 }
8016 } else {
8017 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008018 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008019 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008020 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008021 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008022 return Failure::Exception();
8023 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008024 }
8025 return *value;
8026 }
8027
8028 // Slow case: The property is not in a FixedArray context.
8029 // It is either in an JSObject extension context or it was not found.
8030 Handle<JSObject> context_ext;
8031
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008032 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008033 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008034 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008035 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008036 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008037 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008038
8039 if (strict_mode == kStrictMode) {
8040 // Throw in strict mode (assignment to undefined variable).
8041 Handle<Object> error =
8042 isolate->factory()->NewReferenceError(
8043 "not_defined", HandleVector(&name, 1));
8044 return isolate->Throw(*error);
8045 }
8046 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008047 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008048 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008049 }
8050
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008051 // Set the property, but ignore if read_only variable on the context
8052 // extension object itself.
8053 if ((attributes & READ_ONLY) == 0 ||
8054 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008055 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008056 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008057 SetProperty(context_ext, name, value, NONE, strict_mode));
8058 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008059 // Setting read only property in strict mode.
8060 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008061 isolate->factory()->NewTypeError(
8062 "strict_cannot_assign", HandleVector(&name, 1));
8063 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008064 }
8065 return *value;
8066}
8067
8068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008069RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008070 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008071 ASSERT(args.length() == 1);
8072
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008073 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008074}
8075
8076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008077RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008078 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008079 ASSERT(args.length() == 1);
8080
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008081 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008082}
8083
8084
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008085RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008086 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008087 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008088}
8089
8090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008091RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008092 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008093 ASSERT(args.length() == 1);
8094
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008095 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008096 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008097 isolate->factory()->NewReferenceError("not_defined",
8098 HandleVector(&name, 1));
8099 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008100}
8101
8102
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008103RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008104 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008105
8106 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008107 if (isolate->stack_guard()->IsStackOverflow()) {
8108 NoHandleAllocation na;
8109 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008110 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008111
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008112 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008113}
8114
8115
8116// NOTE: These PrintXXX functions are defined for all builds (not just
8117// DEBUG builds) because we may want to be able to trace function
8118// calls in all modes.
8119static void PrintString(String* str) {
8120 // not uncommon to have empty strings
8121 if (str->length() > 0) {
8122 SmartPointer<char> s =
8123 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8124 PrintF("%s", *s);
8125 }
8126}
8127
8128
8129static void PrintObject(Object* obj) {
8130 if (obj->IsSmi()) {
8131 PrintF("%d", Smi::cast(obj)->value());
8132 } else if (obj->IsString() || obj->IsSymbol()) {
8133 PrintString(String::cast(obj));
8134 } else if (obj->IsNumber()) {
8135 PrintF("%g", obj->Number());
8136 } else if (obj->IsFailure()) {
8137 PrintF("<failure>");
8138 } else if (obj->IsUndefined()) {
8139 PrintF("<undefined>");
8140 } else if (obj->IsNull()) {
8141 PrintF("<null>");
8142 } else if (obj->IsTrue()) {
8143 PrintF("<true>");
8144 } else if (obj->IsFalse()) {
8145 PrintF("<false>");
8146 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008147 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008148 }
8149}
8150
8151
8152static int StackSize() {
8153 int n = 0;
8154 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8155 return n;
8156}
8157
8158
8159static void PrintTransition(Object* result) {
8160 // indentation
8161 { const int nmax = 80;
8162 int n = StackSize();
8163 if (n <= nmax)
8164 PrintF("%4d:%*s", n, n, "");
8165 else
8166 PrintF("%4d:%*s", n, nmax, "...");
8167 }
8168
8169 if (result == NULL) {
8170 // constructor calls
8171 JavaScriptFrameIterator it;
8172 JavaScriptFrame* frame = it.frame();
8173 if (frame->IsConstructor()) PrintF("new ");
8174 // function name
8175 Object* fun = frame->function();
8176 if (fun->IsJSFunction()) {
8177 PrintObject(JSFunction::cast(fun)->shared()->name());
8178 } else {
8179 PrintObject(fun);
8180 }
8181 // function arguments
8182 // (we are intentionally only printing the actually
8183 // supplied parameters, not all parameters required)
8184 PrintF("(this=");
8185 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008186 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008187 for (int i = 0; i < length; i++) {
8188 PrintF(", ");
8189 PrintObject(frame->GetParameter(i));
8190 }
8191 PrintF(") {\n");
8192
8193 } else {
8194 // function result
8195 PrintF("} -> ");
8196 PrintObject(result);
8197 PrintF("\n");
8198 }
8199}
8200
8201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008202RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008203 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008204 NoHandleAllocation ha;
8205 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008206 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008207}
8208
8209
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008210RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008211 NoHandleAllocation ha;
8212 PrintTransition(args[0]);
8213 return args[0]; // return TOS
8214}
8215
8216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008217RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008218 NoHandleAllocation ha;
8219 ASSERT(args.length() == 1);
8220
8221#ifdef DEBUG
8222 if (args[0]->IsString()) {
8223 // If we have a string, assume it's a code "marker"
8224 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008225 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008226 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008227 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8228 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008229 } else {
8230 PrintF("DebugPrint: ");
8231 }
8232 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008233 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008234 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008235 HeapObject::cast(args[0])->map()->Print();
8236 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008237#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008238 // ShortPrint is available in release mode. Print is not.
8239 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008240#endif
8241 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008242 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008243
8244 return args[0]; // return TOS
8245}
8246
8247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008248RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008249 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008250 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008251 isolate->PrintStack();
8252 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008253}
8254
8255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008256RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008257 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008258 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008259
8260 // According to ECMA-262, section 15.9.1, page 117, the precision of
8261 // the number in a Date object representing a particular instant in
8262 // time is milliseconds. Therefore, we floor the result of getting
8263 // the OS time.
8264 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008265 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008266}
8267
8268
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008269RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008270 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008271 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008272
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008273 CONVERT_ARG_CHECKED(String, str, 0);
8274 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008275
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008276 CONVERT_ARG_CHECKED(JSArray, output, 1);
8277 RUNTIME_ASSERT(output->HasFastElements());
8278
8279 AssertNoAllocation no_allocation;
8280
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008281 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008282 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8283 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008284 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008285 result = DateParser::Parse(str->ToAsciiVector(),
8286 output_array,
8287 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008288 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008289 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008290 result = DateParser::Parse(str->ToUC16Vector(),
8291 output_array,
8292 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008293 }
8294
8295 if (result) {
8296 return *output;
8297 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008298 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008299 }
8300}
8301
8302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008303RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008304 NoHandleAllocation ha;
8305 ASSERT(args.length() == 1);
8306
8307 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008308 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008309 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008310}
8311
8312
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008313RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008314 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008315 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008316
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008317 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008318}
8319
8320
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008321RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008322 NoHandleAllocation ha;
8323 ASSERT(args.length() == 1);
8324
8325 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008326 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008327}
8328
8329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008330RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008331 ASSERT(args.length() == 1);
8332 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008333 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008334 return JSGlobalObject::cast(global)->global_receiver();
8335}
8336
8337
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008338RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008339 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008340 ASSERT_EQ(1, args.length());
8341 CONVERT_ARG_CHECKED(String, source, 0);
8342
8343 Handle<Object> result = JsonParser::Parse(source);
8344 if (result.is_null()) {
8345 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008346 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008347 return Failure::Exception();
8348 }
8349 return *result;
8350}
8351
8352
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008353bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8354 Handle<Context> context) {
8355 if (context->allow_code_gen_from_strings()->IsFalse()) {
8356 // Check with callback if set.
8357 AllowCodeGenerationFromStringsCallback callback =
8358 isolate->allow_code_gen_callback();
8359 if (callback == NULL) {
8360 // No callback set and code generation disallowed.
8361 return false;
8362 } else {
8363 // Callback set. Let it decide if code generation is allowed.
8364 VMState state(isolate, EXTERNAL);
8365 return callback(v8::Utils::ToLocal(context));
8366 }
8367 }
8368 return true;
8369}
8370
8371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008372RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008373 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008374 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008375 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008376
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008377 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008378 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008379
8380 // Check if global context allows code generation from
8381 // strings. Throw an exception if it doesn't.
8382 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8383 return isolate->Throw(*isolate->factory()->NewError(
8384 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8385 }
8386
8387 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008388 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8389 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008390 true,
8391 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008392 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008393 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008394 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8395 context,
8396 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008397 return *fun;
8398}
8399
8400
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008401static ObjectPair CompileGlobalEval(Isolate* isolate,
8402 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008403 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008404 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008405 Handle<Context> context = Handle<Context>(isolate->context());
8406 Handle<Context> global_context = Handle<Context>(context->global_context());
8407
8408 // Check if global context allows code generation from
8409 // strings. Throw an exception if it doesn't.
8410 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8411 isolate->Throw(*isolate->factory()->NewError(
8412 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8413 return MakePair(Failure::Exception(), NULL);
8414 }
8415
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008416 // Deal with a normal eval call with a string argument. Compile it
8417 // and return the compiled function bound in the local context.
8418 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8419 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008420 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008421 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008422 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008423 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008424 Handle<JSFunction> compiled =
8425 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008426 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008427 return MakePair(*compiled, *receiver);
8428}
8429
8430
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008431RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008432 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008433
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008434 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008435 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008436 Handle<Object> receiver; // Will be overwritten.
8437
8438 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008439 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008440#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008441 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008442 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008443 StackFrameLocator locator;
8444 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008445 ASSERT(Context::cast(frame->context()) == *context);
8446#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008447
8448 // Find where the 'eval' symbol is bound. It is unaliased only if
8449 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008450 int index = -1;
8451 PropertyAttributes attributes = ABSENT;
8452 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008453 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8454 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008455 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008456 // Stop search when eval is found or when the global context is
8457 // reached.
8458 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008459 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008460 context = Handle<Context>(Context::cast(context->closure()->context()),
8461 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008462 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008463 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008464 }
8465 }
8466
iposva@chromium.org245aa852009-02-10 00:49:54 +00008467 // If eval could not be resolved, it has been deleted and we need to
8468 // throw a reference error.
8469 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008470 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008471 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008472 isolate->factory()->NewReferenceError("not_defined",
8473 HandleVector(&name, 1));
8474 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008475 }
8476
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008477 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008478 // 'eval' is not bound in the global context. Just call the function
8479 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008480 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008481 receiver = Handle<JSObject>(
8482 isolate->context()->global()->global_receiver(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008483 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008484 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008485 }
8486
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008487 // 'eval' is bound in the global context, but it may have been overwritten.
8488 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008489 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008490 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008491 return MakePair(*callee,
8492 isolate->context()->global()->global_receiver());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008493 }
8494
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008495 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008496 return CompileGlobalEval(isolate,
8497 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008498 args.at<Object>(2),
8499 static_cast<StrictModeFlag>(
8500 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008501}
8502
8503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008504RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008505 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008506
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008507 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008508 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008509
8510 // 'eval' is bound in the global context, but it may have been overwritten.
8511 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008512 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008513 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008514 return MakePair(*callee,
8515 isolate->context()->global()->global_receiver());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008516 }
8517
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008518 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008519 return CompileGlobalEval(isolate,
8520 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008521 args.at<Object>(2),
8522 static_cast<StrictModeFlag>(
8523 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008524}
8525
8526
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008527RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008528 // This utility adjusts the property attributes for newly created Function
8529 // object ("new Function(...)") by changing the map.
8530 // All it does is changing the prototype property to enumerable
8531 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008532 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008533 ASSERT(args.length() == 1);
8534 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008535
8536 Handle<Map> map = func->shared()->strict_mode()
8537 ? isolate->strict_mode_function_instance_map()
8538 : isolate->function_instance_map();
8539
8540 ASSERT(func->map()->instance_type() == map->instance_type());
8541 ASSERT(func->map()->instance_size() == map->instance_size());
8542 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008543 return *func;
8544}
8545
8546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008547RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008548 // Allocate a block of memory in NewSpace (filled with a filler).
8549 // Use as fallback for allocation in generated code when NewSpace
8550 // is full.
8551 ASSERT(args.length() == 1);
8552 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8553 int size = size_smi->value();
8554 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8555 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008556 Heap* heap = isolate->heap();
8557 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008558 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008559 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008560 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008561 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008562 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008563 }
8564 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008565 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008566}
8567
8568
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008569// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008570// array. Returns true if the element was pushed on the stack and
8571// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008572RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008573 ASSERT(args.length() == 2);
8574 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008575 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008576 RUNTIME_ASSERT(array->HasFastElements());
8577 int length = Smi::cast(array->length())->value();
8578 FixedArray* elements = FixedArray::cast(array->elements());
8579 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008580 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008581 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008582 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008583 // Strict not needed. Used for cycle detection in Array join implementation.
8584 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8585 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008586 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008588 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008589}
8590
8591
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008592/**
8593 * A simple visitor visits every element of Array's.
8594 * The backend storage can be a fixed array for fast elements case,
8595 * or a dictionary for sparse array. Since Dictionary is a subtype
8596 * of FixedArray, the class can be used by both fast and slow cases.
8597 * The second parameter of the constructor, fast_elements, specifies
8598 * whether the storage is a FixedArray or Dictionary.
8599 *
8600 * An index limit is used to deal with the situation that a result array
8601 * length overflows 32-bit non-negative integer.
8602 */
8603class ArrayConcatVisitor {
8604 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008605 ArrayConcatVisitor(Isolate* isolate,
8606 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008607 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008608 isolate_(isolate),
8609 storage_(Handle<FixedArray>::cast(
8610 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008611 index_offset_(0u),
8612 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008613
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008614 ~ArrayConcatVisitor() {
8615 clear_storage();
8616 }
8617
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008618 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008619 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008620 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008621
8622 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008623 if (index < static_cast<uint32_t>(storage_->length())) {
8624 storage_->set(index, *elm);
8625 return;
8626 }
8627 // Our initial estimate of length was foiled, possibly by
8628 // getters on the arrays increasing the length of later arrays
8629 // during iteration.
8630 // This shouldn't happen in anything but pathological cases.
8631 SetDictionaryMode(index);
8632 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008633 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008634 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008635 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008636 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008637 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008638 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008639 // Dictionary needed to grow.
8640 clear_storage();
8641 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008642 }
8643}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008644
8645 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008646 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8647 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008648 } else {
8649 index_offset_ += delta;
8650 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008651 }
8652
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008653 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008654 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008655 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008656 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008657 Handle<Map> map;
8658 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008659 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008660 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008661 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008662 }
8663 array->set_map(*map);
8664 array->set_length(*length);
8665 array->set_elements(*storage_);
8666 return array;
8667 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008668
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008669 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008670 // Convert storage to dictionary mode.
8671 void SetDictionaryMode(uint32_t index) {
8672 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008673 Handle<FixedArray> current_storage(*storage_);
8674 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008675 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008676 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8677 for (uint32_t i = 0; i < current_length; i++) {
8678 HandleScope loop_scope;
8679 Handle<Object> element(current_storage->get(i));
8680 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008681 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008682 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008683 if (!new_storage.is_identical_to(slow_storage)) {
8684 slow_storage = loop_scope.CloseAndEscape(new_storage);
8685 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008686 }
8687 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008688 clear_storage();
8689 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008690 fast_elements_ = false;
8691 }
8692
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008693 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008694 isolate_->global_handles()->Destroy(
8695 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008696 }
8697
8698 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008699 storage_ = Handle<FixedArray>::cast(
8700 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008701 }
8702
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008703 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008704 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008705 // Index after last seen index. Always less than or equal to
8706 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008707 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008708 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008709};
8710
8711
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008712static uint32_t EstimateElementCount(Handle<JSArray> array) {
8713 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8714 int element_count = 0;
8715 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008716 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008717 // Fast elements can't have lengths that are not representable by
8718 // a 32-bit signed integer.
8719 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8720 int fast_length = static_cast<int>(length);
8721 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8722 for (int i = 0; i < fast_length; i++) {
8723 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008724 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008725 break;
8726 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008727 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008728 Handle<NumberDictionary> dictionary(
8729 NumberDictionary::cast(array->elements()));
8730 int capacity = dictionary->Capacity();
8731 for (int i = 0; i < capacity; i++) {
8732 Handle<Object> key(dictionary->KeyAt(i));
8733 if (dictionary->IsKey(*key)) {
8734 element_count++;
8735 }
8736 }
8737 break;
8738 }
8739 default:
8740 // External arrays are always dense.
8741 return length;
8742 }
8743 // As an estimate, we assume that the prototype doesn't contain any
8744 // inherited elements.
8745 return element_count;
8746}
8747
8748
8749
8750template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008751static void IterateExternalArrayElements(Isolate* isolate,
8752 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008753 bool elements_are_ints,
8754 bool elements_are_guaranteed_smis,
8755 ArrayConcatVisitor* visitor) {
8756 Handle<ExternalArrayClass> array(
8757 ExternalArrayClass::cast(receiver->elements()));
8758 uint32_t len = static_cast<uint32_t>(array->length());
8759
8760 ASSERT(visitor != NULL);
8761 if (elements_are_ints) {
8762 if (elements_are_guaranteed_smis) {
8763 for (uint32_t j = 0; j < len; j++) {
8764 HandleScope loop_scope;
8765 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8766 visitor->visit(j, e);
8767 }
8768 } else {
8769 for (uint32_t j = 0; j < len; j++) {
8770 HandleScope loop_scope;
8771 int64_t val = static_cast<int64_t>(array->get(j));
8772 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8773 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8774 visitor->visit(j, e);
8775 } else {
8776 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008777 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008778 visitor->visit(j, e);
8779 }
8780 }
8781 }
8782 } else {
8783 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008784 HandleScope loop_scope(isolate);
8785 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008786 visitor->visit(j, e);
8787 }
8788 }
8789}
8790
8791
8792// Used for sorting indices in a List<uint32_t>.
8793static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8794 uint32_t a = *ap;
8795 uint32_t b = *bp;
8796 return (a == b) ? 0 : (a < b) ? -1 : 1;
8797}
8798
8799
8800static void CollectElementIndices(Handle<JSObject> object,
8801 uint32_t range,
8802 List<uint32_t>* indices) {
8803 JSObject::ElementsKind kind = object->GetElementsKind();
8804 switch (kind) {
8805 case JSObject::FAST_ELEMENTS: {
8806 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8807 uint32_t length = static_cast<uint32_t>(elements->length());
8808 if (range < length) length = range;
8809 for (uint32_t i = 0; i < length; i++) {
8810 if (!elements->get(i)->IsTheHole()) {
8811 indices->Add(i);
8812 }
8813 }
8814 break;
8815 }
8816 case JSObject::DICTIONARY_ELEMENTS: {
8817 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008818 uint32_t capacity = dict->Capacity();
8819 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008820 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008821 Handle<Object> k(dict->KeyAt(j));
8822 if (dict->IsKey(*k)) {
8823 ASSERT(k->IsNumber());
8824 uint32_t index = static_cast<uint32_t>(k->Number());
8825 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008826 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008827 }
8828 }
8829 }
8830 break;
8831 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008832 default: {
8833 int dense_elements_length;
8834 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008835 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008836 dense_elements_length =
8837 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008838 break;
8839 }
8840 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008841 dense_elements_length =
8842 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008843 break;
8844 }
8845 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008846 dense_elements_length =
8847 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008848 break;
8849 }
8850 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008851 dense_elements_length =
8852 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008853 break;
8854 }
8855 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008856 dense_elements_length =
8857 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008858 break;
8859 }
8860 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008861 dense_elements_length =
8862 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008863 break;
8864 }
8865 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008866 dense_elements_length =
8867 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008868 break;
8869 }
8870 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008871 dense_elements_length =
8872 ExternalFloatArray::cast(object->elements())->length();
8873 break;
8874 }
8875 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
8876 dense_elements_length =
8877 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008878 break;
8879 }
8880 default:
8881 UNREACHABLE();
8882 dense_elements_length = 0;
8883 break;
8884 }
8885 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8886 if (range <= length) {
8887 length = range;
8888 // We will add all indices, so we might as well clear it first
8889 // and avoid duplicates.
8890 indices->Clear();
8891 }
8892 for (uint32_t i = 0; i < length; i++) {
8893 indices->Add(i);
8894 }
8895 if (length == range) return; // All indices accounted for already.
8896 break;
8897 }
8898 }
8899
8900 Handle<Object> prototype(object->GetPrototype());
8901 if (prototype->IsJSObject()) {
8902 // The prototype will usually have no inherited element indices,
8903 // but we have to check.
8904 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8905 }
8906}
8907
8908
8909/**
8910 * A helper function that visits elements of a JSArray in numerical
8911 * order.
8912 *
8913 * The visitor argument called for each existing element in the array
8914 * with the element index and the element's value.
8915 * Afterwards it increments the base-index of the visitor by the array
8916 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008917 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008918 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008919static bool IterateElements(Isolate* isolate,
8920 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008921 ArrayConcatVisitor* visitor) {
8922 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8923 switch (receiver->GetElementsKind()) {
8924 case JSObject::FAST_ELEMENTS: {
8925 // Run through the elements FixedArray and use HasElement and GetElement
8926 // to check the prototype for missing elements.
8927 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8928 int fast_length = static_cast<int>(length);
8929 ASSERT(fast_length <= elements->length());
8930 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008931 HandleScope loop_scope(isolate);
8932 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008933 if (!element_value->IsTheHole()) {
8934 visitor->visit(j, element_value);
8935 } else if (receiver->HasElement(j)) {
8936 // Call GetElement on receiver, not its prototype, or getters won't
8937 // have the correct receiver.
8938 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008939 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008940 visitor->visit(j, element_value);
8941 }
8942 }
8943 break;
8944 }
8945 case JSObject::DICTIONARY_ELEMENTS: {
8946 Handle<NumberDictionary> dict(receiver->element_dictionary());
8947 List<uint32_t> indices(dict->Capacity() / 2);
8948 // Collect all indices in the object and the prototypes less
8949 // than length. This might introduce duplicates in the indices list.
8950 CollectElementIndices(receiver, length, &indices);
8951 indices.Sort(&compareUInt32);
8952 int j = 0;
8953 int n = indices.length();
8954 while (j < n) {
8955 HandleScope loop_scope;
8956 uint32_t index = indices[j];
8957 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008958 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008959 visitor->visit(index, element);
8960 // Skip to next different index (i.e., omit duplicates).
8961 do {
8962 j++;
8963 } while (j < n && indices[j] == index);
8964 }
8965 break;
8966 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008967 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8968 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8969 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008970 for (uint32_t j = 0; j < length; j++) {
8971 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8972 visitor->visit(j, e);
8973 }
8974 break;
8975 }
8976 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8977 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008978 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008979 break;
8980 }
8981 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8982 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008983 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008984 break;
8985 }
8986 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8987 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008988 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008989 break;
8990 }
8991 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8992 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008993 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008994 break;
8995 }
8996 case JSObject::EXTERNAL_INT_ELEMENTS: {
8997 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008998 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008999 break;
9000 }
9001 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9002 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009003 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009004 break;
9005 }
9006 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9007 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009008 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009009 break;
9010 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009011 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9012 IterateExternalArrayElements<ExternalDoubleArray, double>(
9013 isolate, receiver, false, false, visitor);
9014 break;
9015 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009016 default:
9017 UNREACHABLE();
9018 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009019 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009020 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009021 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009022}
9023
9024
9025/**
9026 * Array::concat implementation.
9027 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009028 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009029 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009030 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009031RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009032 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009033 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009034
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009035 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9036 int argument_count = static_cast<int>(arguments->length()->Number());
9037 RUNTIME_ASSERT(arguments->HasFastElements());
9038 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009039
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009040 // Pass 1: estimate the length and number of elements of the result.
9041 // The actual length can be larger if any of the arguments have getters
9042 // that mutate other arguments (but will otherwise be precise).
9043 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009044
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009045 uint32_t estimate_result_length = 0;
9046 uint32_t estimate_nof_elements = 0;
9047 {
9048 for (int i = 0; i < argument_count; i++) {
9049 HandleScope loop_scope;
9050 Handle<Object> obj(elements->get(i));
9051 uint32_t length_estimate;
9052 uint32_t element_estimate;
9053 if (obj->IsJSArray()) {
9054 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9055 length_estimate =
9056 static_cast<uint32_t>(array->length()->Number());
9057 element_estimate =
9058 EstimateElementCount(array);
9059 } else {
9060 length_estimate = 1;
9061 element_estimate = 1;
9062 }
9063 // Avoid overflows by capping at kMaxElementCount.
9064 if (JSObject::kMaxElementCount - estimate_result_length <
9065 length_estimate) {
9066 estimate_result_length = JSObject::kMaxElementCount;
9067 } else {
9068 estimate_result_length += length_estimate;
9069 }
9070 if (JSObject::kMaxElementCount - estimate_nof_elements <
9071 element_estimate) {
9072 estimate_nof_elements = JSObject::kMaxElementCount;
9073 } else {
9074 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009075 }
9076 }
9077 }
9078
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009079 // If estimated number of elements is more than half of length, a
9080 // fixed array (fast case) is more time and space-efficient than a
9081 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009082 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009083
9084 Handle<FixedArray> storage;
9085 if (fast_case) {
9086 // The backing storage array must have non-existing elements to
9087 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009088 storage = isolate->factory()->NewFixedArrayWithHoles(
9089 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009090 } else {
9091 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9092 uint32_t at_least_space_for = estimate_nof_elements +
9093 (estimate_nof_elements >> 2);
9094 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009095 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009096 }
9097
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009098 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009099
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009100 for (int i = 0; i < argument_count; i++) {
9101 Handle<Object> obj(elements->get(i));
9102 if (obj->IsJSArray()) {
9103 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009104 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009105 return Failure::Exception();
9106 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009107 } else {
9108 visitor.visit(0, obj);
9109 visitor.increase_index_offset(1);
9110 }
9111 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009112
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009113 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009114}
9115
9116
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009117// This will not allocate (flatten the string), but it may run
9118// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009119RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009120 NoHandleAllocation ha;
9121 ASSERT(args.length() == 1);
9122
9123 CONVERT_CHECKED(String, string, args[0]);
9124 StringInputBuffer buffer(string);
9125 while (buffer.has_more()) {
9126 uint16_t character = buffer.GetNext();
9127 PrintF("%c", character);
9128 }
9129 return string;
9130}
9131
ager@chromium.org5ec48922009-05-05 07:25:34 +00009132// Moves all own elements of an object, that are below a limit, to positions
9133// starting at zero. All undefined values are placed after non-undefined values,
9134// and are followed by non-existing element. Does not change the length
9135// property.
9136// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009137RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009138 ASSERT(args.length() == 2);
9139 CONVERT_CHECKED(JSObject, object, args[0]);
9140 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9141 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009142}
9143
9144
9145// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009146RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009147 ASSERT(args.length() == 2);
9148 CONVERT_CHECKED(JSArray, from, args[0]);
9149 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009150 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009151 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009152 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9153 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009154 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009155 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009156 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009157 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009158 Object* new_map;
9159 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009160 to->set_map(Map::cast(new_map));
9161 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009162 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009163 Object* obj;
9164 { MaybeObject* maybe_obj = from->ResetElements();
9165 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9166 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009167 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009168 return to;
9169}
9170
9171
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009172// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009173RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009174 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009175 CONVERT_CHECKED(JSObject, object, args[0]);
9176 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009177 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009178 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009179 } else if (object->IsJSArray()) {
9180 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009181 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009182 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009183 }
9184}
9185
9186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009187RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009188 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009189
9190 ASSERT_EQ(3, args.length());
9191
ager@chromium.orgac091b72010-05-05 07:34:42 +00009192 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009193 Handle<Object> key1 = args.at<Object>(1);
9194 Handle<Object> key2 = args.at<Object>(2);
9195
9196 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009197 if (!key1->ToArrayIndex(&index1)
9198 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009199 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009200 }
9201
ager@chromium.orgac091b72010-05-05 07:34:42 +00009202 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9203 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009204 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009205 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009206 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009207
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009208 RETURN_IF_EMPTY_HANDLE(isolate,
9209 SetElement(jsobject, index1, tmp2, kStrictMode));
9210 RETURN_IF_EMPTY_HANDLE(isolate,
9211 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009212
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009213 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009214}
9215
9216
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009217// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009218// might have elements. Can either return keys (positive integers) or
9219// intervals (pair of a negative integer (-start-1) followed by a
9220// positive (length)) or undefined values.
9221// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009222RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009223 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009224 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009225 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009226 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009227 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009228 // Create an array and get all the keys into it, then remove all the
9229 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009230 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009231 int keys_length = keys->length();
9232 for (int i = 0; i < keys_length; i++) {
9233 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009234 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009235 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009236 // Zap invalid keys.
9237 keys->set_undefined(i);
9238 }
9239 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009240 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009241 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009242 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009243 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009245 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009246 uint32_t actual_length =
9247 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009248 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009249 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009250 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009251 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009252 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009253 }
9254}
9255
9256
9257// DefineAccessor takes an optional final argument which is the
9258// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9259// to the way accessors are implemented, it is set for both the getter
9260// and setter on the first call to DefineAccessor and ignored on
9261// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009262RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009263 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9264 // Compute attributes.
9265 PropertyAttributes attributes = NONE;
9266 if (args.length() == 5) {
9267 CONVERT_CHECKED(Smi, attrs, args[4]);
9268 int value = attrs->value();
9269 // Only attribute bits should be set.
9270 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9271 attributes = static_cast<PropertyAttributes>(value);
9272 }
9273
9274 CONVERT_CHECKED(JSObject, obj, args[0]);
9275 CONVERT_CHECKED(String, name, args[1]);
9276 CONVERT_CHECKED(Smi, flag, args[2]);
9277 CONVERT_CHECKED(JSFunction, fun, args[3]);
9278 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9279}
9280
9281
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009282RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009283 ASSERT(args.length() == 3);
9284 CONVERT_CHECKED(JSObject, obj, args[0]);
9285 CONVERT_CHECKED(String, name, args[1]);
9286 CONVERT_CHECKED(Smi, flag, args[2]);
9287 return obj->LookupAccessor(name, flag->value() == 0);
9288}
9289
9290
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009291#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009292RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009293 ASSERT(args.length() == 0);
9294 return Execution::DebugBreakHelper();
9295}
9296
9297
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009298// Helper functions for wrapping and unwrapping stack frame ids.
9299static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009300 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009301 return Smi::FromInt(id >> 2);
9302}
9303
9304
9305static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9306 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9307}
9308
9309
9310// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009311// args[0]: debug event listener function to set or null or undefined for
9312// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009313// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009314RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009315 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009316 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9317 args[0]->IsUndefined() ||
9318 args[0]->IsNull());
9319 Handle<Object> callback = args.at<Object>(0);
9320 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009321 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009323 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009324}
9325
9326
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009327RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009328 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009329 isolate->stack_guard()->DebugBreak();
9330 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009331}
9332
9333
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009334static MaybeObject* DebugLookupResultValue(Heap* heap,
9335 Object* receiver,
9336 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009337 LookupResult* result,
9338 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009339 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009340 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009341 case NORMAL:
9342 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009343 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009344 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009345 }
9346 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009347 case FIELD:
9348 value =
9349 JSObject::cast(
9350 result->holder())->FastPropertyAt(result->GetFieldIndex());
9351 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009352 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009353 }
9354 return value;
9355 case CONSTANT_FUNCTION:
9356 return result->GetConstantFunction();
9357 case CALLBACKS: {
9358 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009359 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009360 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009361 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009362 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009363 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009364 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009365 maybe_value = heap->isolate()->pending_exception();
9366 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009367 if (caught_exception != NULL) {
9368 *caught_exception = true;
9369 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009370 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009371 }
9372 return value;
9373 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009374 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009375 }
9376 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009377 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009378 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009379 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009380 case CONSTANT_TRANSITION:
9381 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009382 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009383 default:
9384 UNREACHABLE();
9385 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009386 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009387 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009388}
9389
9390
ager@chromium.org32912102009-01-16 10:38:43 +00009391// Get debugger related details for an object property.
9392// args[0]: object holding property
9393// args[1]: name of the property
9394//
9395// The array returned contains the following information:
9396// 0: Property value
9397// 1: Property details
9398// 2: Property value is exception
9399// 3: Getter function if defined
9400// 4: Setter function if defined
9401// Items 2-4 are only filled if the property has either a getter or a setter
9402// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009403RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009404 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009405
9406 ASSERT(args.length() == 2);
9407
9408 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9409 CONVERT_ARG_CHECKED(String, name, 1);
9410
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009411 // Make sure to set the current context to the context before the debugger was
9412 // entered (if the debugger is entered). The reason for switching context here
9413 // is that for some property lookups (accessors and interceptors) callbacks
9414 // into the embedding application can occour, and the embedding application
9415 // could have the assumption that its own global context is the current
9416 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009417 SaveContext save(isolate);
9418 if (isolate->debug()->InDebugger()) {
9419 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009420 }
9421
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009422 // Skip the global proxy as it has no properties and always delegates to the
9423 // real global object.
9424 if (obj->IsJSGlobalProxy()) {
9425 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9426 }
9427
9428
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009429 // Check if the name is trivially convertible to an index and get the element
9430 // if so.
9431 uint32_t index;
9432 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009433 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009434 Object* element_or_char;
9435 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009436 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009437 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9438 return maybe_element_or_char;
9439 }
9440 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009441 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009442 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009443 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009444 }
9445
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009446 // Find the number of objects making up this.
9447 int length = LocalPrototypeChainLength(*obj);
9448
9449 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009450 Handle<JSObject> jsproto = obj;
9451 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009452 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009453 jsproto->LocalLookup(*name, &result);
9454 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009455 // LookupResult is not GC safe as it holds raw object pointers.
9456 // GC can happen later in this code so put the required fields into
9457 // local variables using handles when required for later use.
9458 PropertyType result_type = result.type();
9459 Handle<Object> result_callback_obj;
9460 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009461 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9462 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009463 }
9464 Smi* property_details = result.GetPropertyDetails().AsSmi();
9465 // DebugLookupResultValue can cause GC so details from LookupResult needs
9466 // to be copied to handles before this.
9467 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009468 Object* raw_value;
9469 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009470 DebugLookupResultValue(isolate->heap(), *obj, *name,
9471 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009472 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9473 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009474 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009475
9476 // If the callback object is a fixed array then it contains JavaScript
9477 // getter and/or setter.
9478 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9479 result_callback_obj->IsFixedArray();
9480 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009481 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009482 details->set(0, *value);
9483 details->set(1, property_details);
9484 if (hasJavaScriptAccessors) {
9485 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009486 caught_exception ? isolate->heap()->true_value()
9487 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009488 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9489 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9490 }
9491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009492 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009493 }
9494 if (i < length - 1) {
9495 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9496 }
9497 }
9498
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009499 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009500}
9501
9502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009503RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009504 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009505
9506 ASSERT(args.length() == 2);
9507
9508 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9509 CONVERT_ARG_CHECKED(String, name, 1);
9510
9511 LookupResult result;
9512 obj->Lookup(*name, &result);
9513 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009514 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009515 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009516 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009517}
9518
9519
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009520// Return the property type calculated from the property details.
9521// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009522RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009523 ASSERT(args.length() == 1);
9524 CONVERT_CHECKED(Smi, details, args[0]);
9525 PropertyType type = PropertyDetails(details).type();
9526 return Smi::FromInt(static_cast<int>(type));
9527}
9528
9529
9530// Return the property attribute calculated from the property details.
9531// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009532RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009533 ASSERT(args.length() == 1);
9534 CONVERT_CHECKED(Smi, details, args[0]);
9535 PropertyAttributes attributes = PropertyDetails(details).attributes();
9536 return Smi::FromInt(static_cast<int>(attributes));
9537}
9538
9539
9540// Return the property insertion index calculated from the property details.
9541// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009542RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009543 ASSERT(args.length() == 1);
9544 CONVERT_CHECKED(Smi, details, args[0]);
9545 int index = PropertyDetails(details).index();
9546 return Smi::FromInt(index);
9547}
9548
9549
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009550// Return property value from named interceptor.
9551// args[0]: object
9552// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009553RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009554 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009555 ASSERT(args.length() == 2);
9556 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9557 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9558 CONVERT_ARG_CHECKED(String, name, 1);
9559
9560 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009561 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009562}
9563
9564
9565// Return element value from indexed interceptor.
9566// args[0]: object
9567// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009568RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009569 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009570 ASSERT(args.length() == 2);
9571 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9572 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9573 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9574
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009575 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009576}
9577
9578
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009579RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009580 ASSERT(args.length() >= 1);
9581 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009582 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009583 if (isolate->debug()->break_id() == 0 ||
9584 break_id != isolate->debug()->break_id()) {
9585 return isolate->Throw(
9586 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009587 }
9588
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009589 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009590}
9591
9592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009593RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009594 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009595 ASSERT(args.length() == 1);
9596
9597 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009598 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009599 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9600 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009601 if (!maybe_result->ToObject(&result)) return maybe_result;
9602 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009603
9604 // Count all frames which are relevant to debugging stack trace.
9605 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009606 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009607 if (id == StackFrame::NO_ID) {
9608 // If there is no JavaScript stack frame count is 0.
9609 return Smi::FromInt(0);
9610 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009611 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009612 return Smi::FromInt(n);
9613}
9614
9615
9616static const int kFrameDetailsFrameIdIndex = 0;
9617static const int kFrameDetailsReceiverIndex = 1;
9618static const int kFrameDetailsFunctionIndex = 2;
9619static const int kFrameDetailsArgumentCountIndex = 3;
9620static const int kFrameDetailsLocalCountIndex = 4;
9621static const int kFrameDetailsSourcePositionIndex = 5;
9622static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009623static const int kFrameDetailsAtReturnIndex = 7;
9624static const int kFrameDetailsDebuggerFrameIndex = 8;
9625static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009626
9627// Return an array with frame details
9628// args[0]: number: break id
9629// args[1]: number: frame index
9630//
9631// The array returned contains the following information:
9632// 0: Frame id
9633// 1: Receiver
9634// 2: Function
9635// 3: Argument count
9636// 4: Local count
9637// 5: Source position
9638// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009639// 7: Is at return
9640// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009641// Arguments name, value
9642// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009643// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009644RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009645 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009646 ASSERT(args.length() == 2);
9647
9648 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009649 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009650 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9651 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009652 if (!maybe_check->ToObject(&check)) return maybe_check;
9653 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009654 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009655 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009656
9657 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009658 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009659 if (id == StackFrame::NO_ID) {
9660 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009661 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009662 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009663 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009664 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009665 for (; !it.done(); it.Advance()) {
9666 if (count == index) break;
9667 count++;
9668 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009669 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009670
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009671 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009672 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009673
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009674 // Traverse the saved contexts chain to find the active context for the
9675 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009676 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009677 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009678 save = save->prev();
9679 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009680 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009681
9682 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009683 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009684
9685 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009686 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009687 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009688
9689 // Check for constructor frame.
9690 bool constructor = it.frame()->IsConstructor();
9691
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009692 // Get scope info and read from it for local variable information.
9693 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009694 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009695 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009696
9697 // Get the context.
9698 Handle<Context> context(Context::cast(it.frame()->context()));
9699
9700 // Get the locals names and values into a temporary array.
9701 //
9702 // TODO(1240907): Hide compiler-introduced stack variables
9703 // (e.g. .result)? For users of the debugger, they will probably be
9704 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009705 Handle<FixedArray> locals =
9706 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009707
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009708 // Fill in the names of the locals.
9709 for (int i = 0; i < info.NumberOfLocals(); i++) {
9710 locals->set(i * 2, *info.LocalName(i));
9711 }
9712
9713 // Fill in the values of the locals.
9714 for (int i = 0; i < info.NumberOfLocals(); i++) {
9715 if (is_optimized_frame) {
9716 // If we are inspecting an optimized frame use undefined as the
9717 // value for all locals.
9718 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009719 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009720 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009721 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009722 } else if (i < info.number_of_stack_slots()) {
9723 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009724 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9725 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009726 // Traverse the context chain to the function context as all local
9727 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009728 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009729 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009730 context = Handle<Context>(context->previous());
9731 }
9732 ASSERT(context->is_function_context());
9733 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009734 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009735 }
9736 }
9737
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009738 // Check whether this frame is positioned at return. If not top
9739 // frame or if the frame is optimized it cannot be at a return.
9740 bool at_return = false;
9741 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009742 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009743 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009744
9745 // If positioned just before return find the value to be returned and add it
9746 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009747 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009748 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009749 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009750 Address internal_frame_sp = NULL;
9751 while (!it2.done()) {
9752 if (it2.frame()->is_internal()) {
9753 internal_frame_sp = it2.frame()->sp();
9754 } else {
9755 if (it2.frame()->is_java_script()) {
9756 if (it2.frame()->id() == it.frame()->id()) {
9757 // The internal frame just before the JavaScript frame contains the
9758 // value to return on top. A debug break at return will create an
9759 // internal frame to store the return value (eax/rax/r0) before
9760 // entering the debug break exit frame.
9761 if (internal_frame_sp != NULL) {
9762 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009763 Handle<Object>(Memory::Object_at(internal_frame_sp),
9764 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009765 break;
9766 }
9767 }
9768 }
9769
9770 // Indicate that the previous frame was not an internal frame.
9771 internal_frame_sp = NULL;
9772 }
9773 it2.Advance();
9774 }
9775 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009776
9777 // Now advance to the arguments adapter frame (if any). It contains all
9778 // the provided parameters whereas the function frame always have the number
9779 // of arguments matching the functions parameters. The rest of the
9780 // information (except for what is collected above) is the same.
9781 it.AdvanceToArgumentsFrame();
9782
9783 // Find the number of arguments to fill. At least fill the number of
9784 // parameters for the function and fill more if more parameters are provided.
9785 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009786 if (argument_count < it.frame()->ComputeParametersCount()) {
9787 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009788 }
9789
9790 // Calculate the size of the result.
9791 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009792 2 * (argument_count + info.NumberOfLocals()) +
9793 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009794 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009795
9796 // Add the frame id.
9797 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9798
9799 // Add the function (same as in function frame).
9800 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9801
9802 // Add the arguments count.
9803 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9804
9805 // Add the locals count
9806 details->set(kFrameDetailsLocalCountIndex,
9807 Smi::FromInt(info.NumberOfLocals()));
9808
9809 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009810 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009811 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9812 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009813 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009814 }
9815
9816 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009817 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009818
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009819 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009820 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009821
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009822 // Add information on whether this frame is invoked in the debugger context.
9823 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009824 heap->ToBoolean(*save->context() ==
9825 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009826
9827 // Fill the dynamic part.
9828 int details_index = kFrameDetailsFirstDynamicIndex;
9829
9830 // Add arguments name and value.
9831 for (int i = 0; i < argument_count; i++) {
9832 // Name of the argument.
9833 if (i < info.number_of_parameters()) {
9834 details->set(details_index++, *info.parameter_name(i));
9835 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009836 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009837 }
9838
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009839 // Parameter value. If we are inspecting an optimized frame, use
9840 // undefined as the value.
9841 //
9842 // TODO(3141533): We should be able to get the actual parameter
9843 // value for optimized frames.
9844 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009845 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009846 details->set(details_index++, it.frame()->GetParameter(i));
9847 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009848 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009849 }
9850 }
9851
9852 // Add locals name and value from the temporary copy from the function frame.
9853 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9854 details->set(details_index++, locals->get(i));
9855 }
9856
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009857 // Add the value being returned.
9858 if (at_return) {
9859 details->set(details_index++, *return_value);
9860 }
9861
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009862 // Add the receiver (same as in function frame).
9863 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9864 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009865 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009866 if (!receiver->IsJSObject()) {
9867 // If the receiver is NOT a JSObject we have hit an optimization
9868 // where a value object is not converted into a wrapped JS objects.
9869 // To hide this optimization from the debugger, we wrap the receiver
9870 // by creating correct wrapper object based on the calling frame's
9871 // global context.
9872 it.Advance();
9873 Handle<Context> calling_frames_global_context(
9874 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009875 receiver =
9876 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009877 }
9878 details->set(kFrameDetailsReceiverIndex, *receiver);
9879
9880 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009881 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009882}
9883
9884
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009885// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009886static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009887 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009888 Handle<SerializedScopeInfo> serialized_scope_info,
9889 ScopeInfo<>& scope_info,
9890 Handle<Context> context,
9891 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009892 // Fill all context locals to the context extension.
9893 for (int i = Context::MIN_CONTEXT_SLOTS;
9894 i < scope_info.number_of_context_slots();
9895 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009896 int context_index = serialized_scope_info->ContextSlotIndex(
9897 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009898
9899 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009900 if (*scope_info.context_slot_name(i) !=
9901 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009902 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009903 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009904 SetProperty(scope_object,
9905 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009906 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009907 NONE,
9908 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009909 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009910 }
9911 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009912
9913 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009914}
9915
9916
9917// Create a plain JSObject which materializes the local scope for the specified
9918// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009919static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
9920 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009921 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009922 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009923 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9924 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009925
9926 // Allocate and initialize a JSObject with all the arguments, stack locals
9927 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009928 Handle<JSObject> local_scope =
9929 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009930
9931 // First fill all parameters.
9932 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009933 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009934 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009935 SetProperty(local_scope,
9936 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009937 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009938 NONE,
9939 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009940 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009941 }
9942
9943 // Second fill all stack locals.
9944 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009945 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009946 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009947 SetProperty(local_scope,
9948 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009949 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009950 NONE,
9951 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009952 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009953 }
9954
9955 // Third fill all context locals.
9956 Handle<Context> frame_context(Context::cast(frame->context()));
9957 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009958 if (!CopyContextLocalsToScopeObject(isolate,
9959 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009960 function_context, local_scope)) {
9961 return Handle<JSObject>();
9962 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009963
9964 // Finally copy any properties from the function context extension. This will
9965 // be variables introduced by eval.
9966 if (function_context->closure() == *function) {
9967 if (function_context->has_extension() &&
9968 !function_context->IsGlobalContext()) {
9969 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009970 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009971 for (int i = 0; i < keys->length(); i++) {
9972 // Names of variables introduced by eval are strings.
9973 ASSERT(keys->get(i)->IsString());
9974 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009975 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009976 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009977 SetProperty(local_scope,
9978 key,
9979 GetProperty(ext, key),
9980 NONE,
9981 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009982 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009983 }
9984 }
9985 }
9986 return local_scope;
9987}
9988
9989
9990// Create a plain JSObject which materializes the closure content for the
9991// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009992static Handle<JSObject> MaterializeClosure(Isolate* isolate,
9993 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009994 ASSERT(context->is_function_context());
9995
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009996 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009997 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9998 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009999
10000 // Allocate and initialize a JSObject with all the content of theis function
10001 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010002 Handle<JSObject> closure_scope =
10003 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010004
10005 // Check whether the arguments shadow object exists.
10006 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010007 shared->scope_info()->ContextSlotIndex(
10008 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010009 if (arguments_shadow_index >= 0) {
10010 // In this case all the arguments are available in the arguments shadow
10011 // object.
10012 Handle<JSObject> arguments_shadow(
10013 JSObject::cast(context->get(arguments_shadow_index)));
10014 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010015 // We don't expect exception-throwing getters on the arguments shadow.
10016 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010017 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010018 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010019 SetProperty(closure_scope,
10020 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010021 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010022 NONE,
10023 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010024 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010025 }
10026 }
10027
10028 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010029 if (!CopyContextLocalsToScopeObject(isolate,
10030 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010031 context, closure_scope)) {
10032 return Handle<JSObject>();
10033 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010034
10035 // Finally copy any properties from the function context extension. This will
10036 // be variables introduced by eval.
10037 if (context->has_extension()) {
10038 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010039 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010040 for (int i = 0; i < keys->length(); i++) {
10041 // Names of variables introduced by eval are strings.
10042 ASSERT(keys->get(i)->IsString());
10043 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010044 RETURN_IF_EMPTY_HANDLE_VALUE(
10045 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010046 SetProperty(closure_scope,
10047 key,
10048 GetProperty(ext, key),
10049 NONE,
10050 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010051 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010052 }
10053 }
10054
10055 return closure_scope;
10056}
10057
10058
10059// Iterate over the actual scopes visible from a stack frame. All scopes are
10060// backed by an actual context except the local scope, which is inserted
10061// "artifically" in the context chain.
10062class ScopeIterator {
10063 public:
10064 enum ScopeType {
10065 ScopeTypeGlobal = 0,
10066 ScopeTypeLocal,
10067 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010068 ScopeTypeClosure,
10069 // Every catch block contains an implicit with block (its parameter is
10070 // a JSContextExtensionObject) that extends current scope with a variable
10071 // holding exception object. Such with blocks are treated as scopes of their
10072 // own type.
10073 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010074 };
10075
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010076 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10077 : isolate_(isolate),
10078 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010079 function_(JSFunction::cast(frame->function())),
10080 context_(Context::cast(frame->context())),
10081 local_done_(false),
10082 at_local_(false) {
10083
10084 // Check whether the first scope is actually a local scope.
10085 if (context_->IsGlobalContext()) {
10086 // If there is a stack slot for .result then this local scope has been
10087 // created for evaluating top level code and it is not a real local scope.
10088 // Checking for the existence of .result seems fragile, but the scope info
10089 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010090 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010091 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010092 at_local_ = index < 0;
10093 } else if (context_->is_function_context()) {
10094 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010095 } else if (context_->closure() != *function_) {
10096 // The context_ is a with block from the outer function.
10097 ASSERT(context_->has_extension());
10098 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010099 }
10100 }
10101
10102 // More scopes?
10103 bool Done() { return context_.is_null(); }
10104
10105 // Move to the next scope.
10106 void Next() {
10107 // If at a local scope mark the local scope as passed.
10108 if (at_local_) {
10109 at_local_ = false;
10110 local_done_ = true;
10111
10112 // If the current context is not associated with the local scope the
10113 // current context is the next real scope, so don't move to the next
10114 // context in this case.
10115 if (context_->closure() != *function_) {
10116 return;
10117 }
10118 }
10119
10120 // The global scope is always the last in the chain.
10121 if (context_->IsGlobalContext()) {
10122 context_ = Handle<Context>();
10123 return;
10124 }
10125
10126 // Move to the next context.
10127 if (context_->is_function_context()) {
10128 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
10129 } else {
10130 context_ = Handle<Context>(context_->previous());
10131 }
10132
10133 // If passing the local scope indicate that the current scope is now the
10134 // local scope.
10135 if (!local_done_ &&
10136 (context_->IsGlobalContext() || (context_->is_function_context()))) {
10137 at_local_ = true;
10138 }
10139 }
10140
10141 // Return the type of the current scope.
10142 int Type() {
10143 if (at_local_) {
10144 return ScopeTypeLocal;
10145 }
10146 if (context_->IsGlobalContext()) {
10147 ASSERT(context_->global()->IsGlobalObject());
10148 return ScopeTypeGlobal;
10149 }
10150 if (context_->is_function_context()) {
10151 return ScopeTypeClosure;
10152 }
10153 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +000010154 // Current scope is either an explicit with statement or a with statement
10155 // implicitely generated for a catch block.
10156 // If the extension object here is a JSContextExtensionObject then
10157 // current with statement is one frome a catch block otherwise it's a
10158 // regular with statement.
10159 if (context_->extension()->IsJSContextExtensionObject()) {
10160 return ScopeTypeCatch;
10161 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010162 return ScopeTypeWith;
10163 }
10164
10165 // Return the JavaScript object with the content of the current scope.
10166 Handle<JSObject> ScopeObject() {
10167 switch (Type()) {
10168 case ScopeIterator::ScopeTypeGlobal:
10169 return Handle<JSObject>(CurrentContext()->global());
10170 break;
10171 case ScopeIterator::ScopeTypeLocal:
10172 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010173 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010174 break;
10175 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010176 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010177 // Return the with object.
10178 return Handle<JSObject>(CurrentContext()->extension());
10179 break;
10180 case ScopeIterator::ScopeTypeClosure:
10181 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010182 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010183 break;
10184 }
10185 UNREACHABLE();
10186 return Handle<JSObject>();
10187 }
10188
10189 // Return the context for this scope. For the local context there might not
10190 // be an actual context.
10191 Handle<Context> CurrentContext() {
10192 if (at_local_ && context_->closure() != *function_) {
10193 return Handle<Context>();
10194 }
10195 return context_;
10196 }
10197
10198#ifdef DEBUG
10199 // Debug print of the content of the current scope.
10200 void DebugPrint() {
10201 switch (Type()) {
10202 case ScopeIterator::ScopeTypeGlobal:
10203 PrintF("Global:\n");
10204 CurrentContext()->Print();
10205 break;
10206
10207 case ScopeIterator::ScopeTypeLocal: {
10208 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010209 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010210 scope_info.Print();
10211 if (!CurrentContext().is_null()) {
10212 CurrentContext()->Print();
10213 if (CurrentContext()->has_extension()) {
10214 Handle<JSObject> extension =
10215 Handle<JSObject>(CurrentContext()->extension());
10216 if (extension->IsJSContextExtensionObject()) {
10217 extension->Print();
10218 }
10219 }
10220 }
10221 break;
10222 }
10223
10224 case ScopeIterator::ScopeTypeWith: {
10225 PrintF("With:\n");
10226 Handle<JSObject> extension =
10227 Handle<JSObject>(CurrentContext()->extension());
10228 extension->Print();
10229 break;
10230 }
10231
ager@chromium.orga1645e22009-09-09 19:27:10 +000010232 case ScopeIterator::ScopeTypeCatch: {
10233 PrintF("Catch:\n");
10234 Handle<JSObject> extension =
10235 Handle<JSObject>(CurrentContext()->extension());
10236 extension->Print();
10237 break;
10238 }
10239
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010240 case ScopeIterator::ScopeTypeClosure: {
10241 PrintF("Closure:\n");
10242 CurrentContext()->Print();
10243 if (CurrentContext()->has_extension()) {
10244 Handle<JSObject> extension =
10245 Handle<JSObject>(CurrentContext()->extension());
10246 if (extension->IsJSContextExtensionObject()) {
10247 extension->Print();
10248 }
10249 }
10250 break;
10251 }
10252
10253 default:
10254 UNREACHABLE();
10255 }
10256 PrintF("\n");
10257 }
10258#endif
10259
10260 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010261 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010262 JavaScriptFrame* frame_;
10263 Handle<JSFunction> function_;
10264 Handle<Context> context_;
10265 bool local_done_;
10266 bool at_local_;
10267
10268 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10269};
10270
10271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010272RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010273 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010274 ASSERT(args.length() == 2);
10275
10276 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010277 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010278 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10279 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010280 if (!maybe_check->ToObject(&check)) return maybe_check;
10281 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010282 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10283
10284 // Get the frame where the debugging is performed.
10285 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010286 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010287 JavaScriptFrame* frame = it.frame();
10288
10289 // Count the visible scopes.
10290 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010291 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010292 n++;
10293 }
10294
10295 return Smi::FromInt(n);
10296}
10297
10298
10299static const int kScopeDetailsTypeIndex = 0;
10300static const int kScopeDetailsObjectIndex = 1;
10301static const int kScopeDetailsSize = 2;
10302
10303// Return an array with scope details
10304// args[0]: number: break id
10305// args[1]: number: frame index
10306// args[2]: number: scope index
10307//
10308// The array returned contains the following information:
10309// 0: Scope type
10310// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010311RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010312 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010313 ASSERT(args.length() == 3);
10314
10315 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010316 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010317 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10318 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010319 if (!maybe_check->ToObject(&check)) return maybe_check;
10320 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010321 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10322 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10323
10324 // Get the frame where the debugging is performed.
10325 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010326 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010327 JavaScriptFrame* frame = frame_it.frame();
10328
10329 // Find the requested scope.
10330 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010331 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010332 for (; !it.Done() && n < index; it.Next()) {
10333 n++;
10334 }
10335 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010336 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010337 }
10338
10339 // Calculate the size of the result.
10340 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010341 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010342
10343 // Fill in scope details.
10344 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010345 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010346 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010347 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010348
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010349 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010350}
10351
10352
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010353RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010354 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010355 ASSERT(args.length() == 0);
10356
10357#ifdef DEBUG
10358 // Print the scopes for the top frame.
10359 StackFrameLocator locator;
10360 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010361 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010362 it.DebugPrint();
10363 }
10364#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010365 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010366}
10367
10368
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010369RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010370 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010371 ASSERT(args.length() == 1);
10372
10373 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010374 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010375 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10376 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010377 if (!maybe_result->ToObject(&result)) return maybe_result;
10378 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010379
10380 // Count all archived V8 threads.
10381 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010382 for (ThreadState* thread =
10383 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010384 thread != NULL;
10385 thread = thread->Next()) {
10386 n++;
10387 }
10388
10389 // Total number of threads is current thread and archived threads.
10390 return Smi::FromInt(n + 1);
10391}
10392
10393
10394static const int kThreadDetailsCurrentThreadIndex = 0;
10395static const int kThreadDetailsThreadIdIndex = 1;
10396static const int kThreadDetailsSize = 2;
10397
10398// Return an array with thread details
10399// args[0]: number: break id
10400// args[1]: number: thread index
10401//
10402// The array returned contains the following information:
10403// 0: Is current thread?
10404// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010405RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010406 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010407 ASSERT(args.length() == 2);
10408
10409 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010410 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010411 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10412 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010413 if (!maybe_check->ToObject(&check)) return maybe_check;
10414 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010415 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10416
10417 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010418 Handle<FixedArray> details =
10419 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010420
10421 // Thread index 0 is current thread.
10422 if (index == 0) {
10423 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010424 details->set(kThreadDetailsCurrentThreadIndex,
10425 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010426 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010427 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010428 } else {
10429 // Find the thread with the requested index.
10430 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010431 ThreadState* thread =
10432 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010433 while (index != n && thread != NULL) {
10434 thread = thread->Next();
10435 n++;
10436 }
10437 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010438 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010439 }
10440
10441 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010442 details->set(kThreadDetailsCurrentThreadIndex,
10443 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010444 details->set(kThreadDetailsThreadIdIndex,
10445 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010446 }
10447
10448 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010449 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010450}
10451
10452
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010453// Sets the disable break state
10454// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010455RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010456 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010457 ASSERT(args.length() == 1);
10458 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010459 isolate->debug()->set_disable_break(disable_break);
10460 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010461}
10462
10463
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010464RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010465 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010466 ASSERT(args.length() == 1);
10467
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010468 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10469 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010470 // Find the number of break points
10471 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010472 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010473 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010474 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010475 Handle<FixedArray>::cast(break_locations));
10476}
10477
10478
10479// Set a break point in a function
10480// args[0]: function
10481// args[1]: number: break source position (within the function source)
10482// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010483RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010484 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010485 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010486 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10487 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010488 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10489 RUNTIME_ASSERT(source_position >= 0);
10490 Handle<Object> break_point_object_arg = args.at<Object>(2);
10491
10492 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010493 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10494 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010495
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010496 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010497}
10498
10499
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010500Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10501 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010502 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010503 // Iterate the heap looking for SharedFunctionInfo generated from the
10504 // script. The inner most SharedFunctionInfo containing the source position
10505 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010506 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010507 // which is found is not compiled it is compiled and the heap is iterated
10508 // again as the compilation might create inner functions from the newly
10509 // compiled function and the actual requested break point might be in one of
10510 // these functions.
10511 bool done = false;
10512 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010513 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010514 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010515 while (!done) {
10516 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010517 for (HeapObject* obj = iterator.next();
10518 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010519 if (obj->IsSharedFunctionInfo()) {
10520 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10521 if (shared->script() == *script) {
10522 // If the SharedFunctionInfo found has the requested script data and
10523 // contains the source position it is a candidate.
10524 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010525 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010526 start_position = shared->start_position();
10527 }
10528 if (start_position <= position &&
10529 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010530 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010531 // candidate this is the new candidate.
10532 if (target.is_null()) {
10533 target_start_position = start_position;
10534 target = shared;
10535 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010536 if (target_start_position == start_position &&
10537 shared->end_position() == target->end_position()) {
10538 // If a top-level function contain only one function
10539 // declartion the source for the top-level and the function is
10540 // the same. In that case prefer the non top-level function.
10541 if (!shared->is_toplevel()) {
10542 target_start_position = start_position;
10543 target = shared;
10544 }
10545 } else if (target_start_position <= start_position &&
10546 shared->end_position() <= target->end_position()) {
10547 // This containment check includes equality as a function inside
10548 // a top-level function can share either start or end position
10549 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010550 target_start_position = start_position;
10551 target = shared;
10552 }
10553 }
10554 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010555 }
10556 }
10557 }
10558
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010559 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010560 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010561 }
10562
10563 // If the candidate found is compiled we are done. NOTE: when lazy
10564 // compilation of inner functions is introduced some additional checking
10565 // needs to be done here to compile inner functions.
10566 done = target->is_compiled();
10567 if (!done) {
10568 // If the candidate is not compiled compile it to reveal any inner
10569 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010570 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010571 }
10572 }
10573
10574 return *target;
10575}
10576
10577
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010578// Changes the state of a break point in a script and returns source position
10579// where break point was set. NOTE: Regarding performance see the NOTE for
10580// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010581// args[0]: script to set break point in
10582// args[1]: number: break source position (within the script source)
10583// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010584RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010585 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010586 ASSERT(args.length() == 3);
10587 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10588 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10589 RUNTIME_ASSERT(source_position >= 0);
10590 Handle<Object> break_point_object_arg = args.at<Object>(2);
10591
10592 // Get the script from the script wrapper.
10593 RUNTIME_ASSERT(wrapper->value()->IsScript());
10594 Handle<Script> script(Script::cast(wrapper->value()));
10595
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010596 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010597 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010598 if (!result->IsUndefined()) {
10599 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10600 // Find position within function. The script position might be before the
10601 // source position of the first function.
10602 int position;
10603 if (shared->start_position() > source_position) {
10604 position = 0;
10605 } else {
10606 position = source_position - shared->start_position();
10607 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010608 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010609 position += shared->start_position();
10610 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010611 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010612 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010613}
10614
10615
10616// Clear a break point
10617// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010618RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010619 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010620 ASSERT(args.length() == 1);
10621 Handle<Object> break_point_object_arg = args.at<Object>(0);
10622
10623 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010624 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010625
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010626 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010627}
10628
10629
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010630// Change the state of break on exceptions.
10631// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10632// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010633RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010634 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010635 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010636 RUNTIME_ASSERT(args[0]->IsNumber());
10637 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010638
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010639 // If the number doesn't match an enum value, the ChangeBreakOnException
10640 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010641 ExceptionBreakType type =
10642 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010643 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010644 isolate->debug()->ChangeBreakOnException(type, enable);
10645 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010646}
10647
10648
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010649// Returns the state of break on exceptions
10650// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010651RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010652 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010653 ASSERT(args.length() == 1);
10654 RUNTIME_ASSERT(args[0]->IsNumber());
10655
10656 ExceptionBreakType type =
10657 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010658 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010659 return Smi::FromInt(result);
10660}
10661
10662
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010663// Prepare for stepping
10664// args[0]: break id for checking execution state
10665// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010666// args[2]: number of times to perform the step, for step out it is the number
10667// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010668RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010669 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010670 ASSERT(args.length() == 3);
10671 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010672 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010673 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10674 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010675 if (!maybe_check->ToObject(&check)) return maybe_check;
10676 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010677 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010678 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010679 }
10680
10681 // Get the step action and check validity.
10682 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10683 if (step_action != StepIn &&
10684 step_action != StepNext &&
10685 step_action != StepOut &&
10686 step_action != StepInMin &&
10687 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010688 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010689 }
10690
10691 // Get the number of steps.
10692 int step_count = NumberToInt32(args[2]);
10693 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010694 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010695 }
10696
ager@chromium.orga1645e22009-09-09 19:27:10 +000010697 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010698 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010699
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010700 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010701 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10702 step_count);
10703 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010704}
10705
10706
10707// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010708RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010709 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010710 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010711 isolate->debug()->ClearStepping();
10712 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010713}
10714
10715
10716// Creates a copy of the with context chain. The copy of the context chain is
10717// is linked to the function context supplied.
10718static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10719 Handle<Context> function_context) {
10720 // At the bottom of the chain. Return the function context to link to.
10721 if (context_chain->is_function_context()) {
10722 return function_context;
10723 }
10724
10725 // Recursively copy the with contexts.
10726 Handle<Context> previous(context_chain->previous());
10727 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
danno@chromium.org160a7b02011-04-18 15:51:38 +000010728 Handle<Context> context = CopyWithContextChain(previous, function_context);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010729 return context->GetIsolate()->factory()->NewWithContext(
10730 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010731}
10732
10733
10734// Helper function to find or create the arguments object for
10735// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010736static Handle<Object> GetArgumentsObject(Isolate* isolate,
10737 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010738 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010739 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010740 const ScopeInfo<>* sinfo,
10741 Handle<Context> function_context) {
10742 // Try to find the value of 'arguments' to pass as parameter. If it is not
10743 // found (that is the debugged function does not reference 'arguments' and
10744 // does not support eval) then create an 'arguments' object.
10745 int index;
10746 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010747 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010748 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010749 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010750 }
10751 }
10752
10753 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010754 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10755 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010756 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010757 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010758 }
10759 }
10760
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010761 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010762 Handle<JSObject> arguments =
10763 isolate->factory()->NewArgumentsObject(function, length);
10764 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010765
10766 AssertNoAllocation no_gc;
10767 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010768 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010769 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010770 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010771 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010772 return arguments;
10773}
10774
10775
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010776static const char kSourceStr[] =
10777 "(function(arguments,__source__){return eval(__source__);})";
10778
10779
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010780// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010781// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010782// extension part has all the parameters and locals of the function on the
10783// stack frame. A function which calls eval with the code to evaluate is then
10784// compiled in this context and called in this context. As this context
10785// replaces the context of the function on the stack frame a new (empty)
10786// function is created as well to be used as the closure for the context.
10787// This function and the context acts as replacements for the function on the
10788// stack frame presenting the same view of the values of parameters and
10789// local variables as if the piece of JavaScript was evaluated at the point
10790// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010791RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010792 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010793
10794 // Check the execution state and decode arguments frame and source to be
10795 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010796 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010797 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010798 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10799 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010800 if (!maybe_check_result->ToObject(&check_result)) {
10801 return maybe_check_result;
10802 }
10803 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010804 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10805 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010806 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010807 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010808
10809 // Handle the processing of break.
10810 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010811
10812 // Get the frame where the debugging is performed.
10813 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010814 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010815 JavaScriptFrame* frame = it.frame();
10816 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010817 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010818 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010819
10820 // Traverse the saved contexts chain to find the active context for the
10821 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010822 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010823 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010824 save = save->prev();
10825 }
10826 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010827 SaveContext savex(isolate);
10828 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010829
10830 // Create the (empty) function replacing the function on the stack frame for
10831 // the purpose of evaluating in the context created below. It is important
10832 // that this function does not describe any parameters and local variables
10833 // in the context. If it does then this will cause problems with the lookup
10834 // in Context::Lookup, where context slots for parameters and local variables
10835 // are looked at before the extension object.
10836 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010837 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10838 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010839 go_between->set_context(function->context());
10840#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010841 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010842 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10843 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10844#endif
10845
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010846 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010847 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10848 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010849
10850 // Allocate a new context for the debug evaluation and set the extension
10851 // object build.
10852 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010853 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10854 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010855 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010856 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010857 Handle<Context> frame_context(Context::cast(frame->context()));
10858 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010859 context = CopyWithContextChain(frame_context, context);
10860
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010861 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010862 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010863 Handle<JSObject>::cast(additional_context), false);
10864 }
10865
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010866 // Wrap the evaluation statement in a new function compiled in the newly
10867 // created context. The function has one parameter which has to be called
10868 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010869 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010870 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010871
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010872 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010873 isolate->factory()->NewStringFromAscii(
10874 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010875
10876 // Currently, the eval code will be executed in non-strict mode,
10877 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010878 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010879 Compiler::CompileEval(function_source,
10880 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010881 context->IsGlobalContext(),
10882 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010883 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010884 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010885 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010886
10887 // Invoke the result of the compilation to get the evaluation function.
10888 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010889 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010890 Handle<Object> evaluation_function =
10891 Execution::Call(compiled_function, receiver, 0, NULL,
10892 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010893 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010894
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010895 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
10896 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010897 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010898
10899 // Invoke the evaluation function and return the result.
10900 const int argc = 2;
10901 Object** argv[argc] = { arguments.location(),
10902 Handle<Object>::cast(source).location() };
10903 Handle<Object> result =
10904 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10905 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010906 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010907
10908 // Skip the global proxy as it has no properties and always delegates to the
10909 // real global object.
10910 if (result->IsJSGlobalProxy()) {
10911 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10912 }
10913
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010914 return *result;
10915}
10916
10917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010918RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010919 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010920
10921 // Check the execution state and decode arguments frame and source to be
10922 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010923 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010924 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010925 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10926 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010927 if (!maybe_check_result->ToObject(&check_result)) {
10928 return maybe_check_result;
10929 }
10930 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010931 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010932 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010933 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010934
10935 // Handle the processing of break.
10936 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010937
10938 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010939 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010940 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010941 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010942 top = top->prev();
10943 }
10944 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010945 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010946 }
10947
10948 // Get the global context now set to the top context from before the
10949 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010950 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010951
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010952 bool is_global = true;
10953
10954 if (additional_context->IsJSObject()) {
10955 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010956 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10957 isolate->factory()->empty_string(),
10958 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010959 go_between->set_context(*context);
10960 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010961 isolate->factory()->NewFunctionContext(
10962 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010963 context->set_extension(JSObject::cast(*additional_context));
10964 is_global = false;
10965 }
10966
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010967 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010968 // Currently, the eval code will be executed in non-strict mode,
10969 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010970 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010971 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010972 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010973 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010974 Handle<JSFunction>(
10975 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10976 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010977
10978 // Invoke the result of the compilation to get the evaluation function.
10979 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010980 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010981 Handle<Object> result =
10982 Execution::Call(compiled_function, receiver, 0, NULL,
10983 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010984 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010985 return *result;
10986}
10987
10988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010989RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010990 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010991 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010992
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010993 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010994 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010995
10996 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010997 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010998 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10999 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11000 // because using
11001 // instances->set(i, *GetScriptWrapper(script))
11002 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11003 // already have deferenced the instances handle.
11004 Handle<JSValue> wrapper = GetScriptWrapper(script);
11005 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011006 }
11007
11008 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011009 Handle<JSObject> result =
11010 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011011 Handle<JSArray>::cast(result)->SetContent(*instances);
11012 return *result;
11013}
11014
11015
11016// Helper function used by Runtime_DebugReferencedBy below.
11017static int DebugReferencedBy(JSObject* target,
11018 Object* instance_filter, int max_references,
11019 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011020 JSFunction* arguments_function) {
11021 NoHandleAllocation ha;
11022 AssertNoAllocation no_alloc;
11023
11024 // Iterate the heap.
11025 int count = 0;
11026 JSObject* last = NULL;
11027 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011028 HeapObject* heap_obj = NULL;
11029 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011030 (max_references == 0 || count < max_references)) {
11031 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011032 if (heap_obj->IsJSObject()) {
11033 // Skip context extension objects and argument arrays as these are
11034 // checked in the context of functions using them.
11035 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011036 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011037 obj->map()->constructor() == arguments_function) {
11038 continue;
11039 }
11040
11041 // Check if the JS object has a reference to the object looked for.
11042 if (obj->ReferencesObject(target)) {
11043 // Check instance filter if supplied. This is normally used to avoid
11044 // references from mirror objects (see Runtime_IsInPrototypeChain).
11045 if (!instance_filter->IsUndefined()) {
11046 Object* V = obj;
11047 while (true) {
11048 Object* prototype = V->GetPrototype();
11049 if (prototype->IsNull()) {
11050 break;
11051 }
11052 if (instance_filter == prototype) {
11053 obj = NULL; // Don't add this object.
11054 break;
11055 }
11056 V = prototype;
11057 }
11058 }
11059
11060 if (obj != NULL) {
11061 // Valid reference found add to instance array if supplied an update
11062 // count.
11063 if (instances != NULL && count < instances_size) {
11064 instances->set(count, obj);
11065 }
11066 last = obj;
11067 count++;
11068 }
11069 }
11070 }
11071 }
11072
11073 // Check for circular reference only. This can happen when the object is only
11074 // referenced from mirrors and has a circular reference in which case the
11075 // object is not really alive and would have been garbage collected if not
11076 // referenced from the mirror.
11077 if (count == 1 && last == target) {
11078 count = 0;
11079 }
11080
11081 // Return the number of referencing objects found.
11082 return count;
11083}
11084
11085
11086// Scan the heap for objects with direct references to an object
11087// args[0]: the object to find references to
11088// args[1]: constructor function for instances to exclude (Mirror)
11089// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011090RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011091 ASSERT(args.length() == 3);
11092
11093 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011094 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011095
11096 // Check parameters.
11097 CONVERT_CHECKED(JSObject, target, args[0]);
11098 Object* instance_filter = args[1];
11099 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11100 instance_filter->IsJSObject());
11101 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11102 RUNTIME_ASSERT(max_references >= 0);
11103
11104 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011105 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011106 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011107 JSFunction* arguments_function =
11108 JSFunction::cast(arguments_boilerplate->map()->constructor());
11109
11110 // Get the number of referencing objects.
11111 int count;
11112 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011113 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011114
11115 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011116 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011117 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011118 if (!maybe_object->ToObject(&object)) return maybe_object;
11119 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011120 FixedArray* instances = FixedArray::cast(object);
11121
11122 // Fill the referencing objects.
11123 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011124 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011125
11126 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011127 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011128 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11129 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011130 if (!maybe_result->ToObject(&result)) return maybe_result;
11131 }
11132 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011133 return result;
11134}
11135
11136
11137// Helper function used by Runtime_DebugConstructedBy below.
11138static int DebugConstructedBy(JSFunction* constructor, int max_references,
11139 FixedArray* instances, int instances_size) {
11140 AssertNoAllocation no_alloc;
11141
11142 // Iterate the heap.
11143 int count = 0;
11144 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011145 HeapObject* heap_obj = NULL;
11146 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011147 (max_references == 0 || count < max_references)) {
11148 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011149 if (heap_obj->IsJSObject()) {
11150 JSObject* obj = JSObject::cast(heap_obj);
11151 if (obj->map()->constructor() == constructor) {
11152 // Valid reference found add to instance array if supplied an update
11153 // count.
11154 if (instances != NULL && count < instances_size) {
11155 instances->set(count, obj);
11156 }
11157 count++;
11158 }
11159 }
11160 }
11161
11162 // Return the number of referencing objects found.
11163 return count;
11164}
11165
11166
11167// Scan the heap for objects constructed by a specific function.
11168// args[0]: the constructor to find instances of
11169// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011170RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011171 ASSERT(args.length() == 2);
11172
11173 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011174 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011175
11176 // Check parameters.
11177 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11178 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11179 RUNTIME_ASSERT(max_references >= 0);
11180
11181 // Get the number of referencing objects.
11182 int count;
11183 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11184
11185 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011186 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011187 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011188 if (!maybe_object->ToObject(&object)) return maybe_object;
11189 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011190 FixedArray* instances = FixedArray::cast(object);
11191
11192 // Fill the referencing objects.
11193 count = DebugConstructedBy(constructor, max_references, instances, count);
11194
11195 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011196 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011197 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11198 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011199 if (!maybe_result->ToObject(&result)) return maybe_result;
11200 }
11201 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011202 return result;
11203}
11204
11205
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011206// Find the effective prototype object as returned by __proto__.
11207// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011208RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011209 ASSERT(args.length() == 1);
11210
11211 CONVERT_CHECKED(JSObject, obj, args[0]);
11212
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011213 // Use the __proto__ accessor.
11214 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011215}
11216
11217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011218RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011219 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011220 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011221 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011222}
11223
11224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011225RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011226#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011227 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011228 ASSERT(args.length() == 1);
11229 // Get the function and make sure it is compiled.
11230 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011231 Handle<SharedFunctionInfo> shared(func->shared());
11232 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011233 return Failure::Exception();
11234 }
11235 func->code()->PrintLn();
11236#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011237 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011238}
ager@chromium.org9085a012009-05-11 19:22:57 +000011239
11240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011241RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011242#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011243 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011244 ASSERT(args.length() == 1);
11245 // Get the function and make sure it is compiled.
11246 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011247 Handle<SharedFunctionInfo> shared(func->shared());
11248 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011249 return Failure::Exception();
11250 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011251 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011252#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011253 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011254}
11255
11256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011257RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011258 NoHandleAllocation ha;
11259 ASSERT(args.length() == 1);
11260
11261 CONVERT_CHECKED(JSFunction, f, args[0]);
11262 return f->shared()->inferred_name();
11263}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011264
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011265
11266static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011267 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011268 AssertNoAllocation no_allocations;
11269
11270 int counter = 0;
11271 int buffer_size = buffer->length();
11272 HeapIterator iterator;
11273 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11274 ASSERT(obj != NULL);
11275 if (!obj->IsSharedFunctionInfo()) {
11276 continue;
11277 }
11278 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11279 if (shared->script() != script) {
11280 continue;
11281 }
11282 if (counter < buffer_size) {
11283 buffer->set(counter, shared);
11284 }
11285 counter++;
11286 }
11287 return counter;
11288}
11289
11290// For a script finds all SharedFunctionInfo's in the heap that points
11291// to this script. Returns JSArray of SharedFunctionInfo wrapped
11292// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011293RUNTIME_FUNCTION(MaybeObject*,
11294 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011295 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011296 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011297 CONVERT_CHECKED(JSValue, script_value, args[0]);
11298
11299 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11300
11301 const int kBufferSize = 32;
11302
11303 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011304 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011305 int number = FindSharedFunctionInfosForScript(*script, *array);
11306 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011307 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011308 FindSharedFunctionInfosForScript(*script, *array);
11309 }
11310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011311 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011312 result->set_length(Smi::FromInt(number));
11313
11314 LiveEdit::WrapSharedFunctionInfos(result);
11315
11316 return *result;
11317}
11318
11319// For a script calculates compilation information about all its functions.
11320// The script source is explicitly specified by the second argument.
11321// The source of the actual script is not used, however it is important that
11322// all generated code keeps references to this particular instance of script.
11323// Returns a JSArray of compilation infos. The array is ordered so that
11324// each function with all its descendant is always stored in a continues range
11325// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011326RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011327 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011328 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011329 CONVERT_CHECKED(JSValue, script, args[0]);
11330 CONVERT_ARG_CHECKED(String, source, 1);
11331 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11332
11333 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11334
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011335 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011336 return Failure::Exception();
11337 }
11338
11339 return result;
11340}
11341
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011342// Changes the source of the script to a new_source.
11343// If old_script_name is provided (i.e. is a String), also creates a copy of
11344// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011345RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011346 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011347 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011348 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11349 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011350 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011351
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011352 CONVERT_CHECKED(Script, original_script_pointer,
11353 original_script_value->value());
11354 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011355
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011356 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11357 new_source,
11358 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011359
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011360 if (old_script->IsScript()) {
11361 Handle<Script> script_handle(Script::cast(old_script));
11362 return *(GetScriptWrapper(script_handle));
11363 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011364 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011365 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011366}
11367
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011368
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011369RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011370 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011371 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011372 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11373 return LiveEdit::FunctionSourceUpdated(shared_info);
11374}
11375
11376
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011377// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011378RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011379 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011380 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011381 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11382 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11383
ager@chromium.orgac091b72010-05-05 07:34:42 +000011384 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011385}
11386
11387// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011388RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011389 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011390 HandleScope scope(isolate);
11391 Handle<Object> function_object(args[0], isolate);
11392 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011393
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011394 if (function_object->IsJSValue()) {
11395 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11396 if (script_object->IsJSValue()) {
11397 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011398 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011399 }
11400
11401 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11402 } else {
11403 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11404 // and we check it in this function.
11405 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011406
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011407 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011408}
11409
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011410
11411// In a code of a parent function replaces original function as embedded object
11412// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011413RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011414 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011415 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011416
11417 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11418 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11419 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11420
11421 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11422 subst_wrapper);
11423
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011424 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011425}
11426
11427
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011428// Updates positions of a shared function info (first parameter) according
11429// to script source change. Text change is described in second parameter as
11430// array of groups of 3 numbers:
11431// (change_begin, change_end, change_end_new_position).
11432// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011433RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011434 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011435 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011436 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11437 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11438
ager@chromium.orgac091b72010-05-05 07:34:42 +000011439 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011440}
11441
11442
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011443// For array of SharedFunctionInfo's (each wrapped in JSValue)
11444// checks that none of them have activations on stacks (of any thread).
11445// Returns array of the same length with corresponding results of
11446// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011447RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011448 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011449 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011450 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011451 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011452
ager@chromium.org357bf652010-04-12 11:30:10 +000011453 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011454}
11455
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011456// Compares 2 strings line-by-line, then token-wise and returns diff in form
11457// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11458// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011459RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011460 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011461 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011462 CONVERT_ARG_CHECKED(String, s1, 0);
11463 CONVERT_ARG_CHECKED(String, s2, 1);
11464
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011465 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011466}
11467
11468
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011469// A testing entry. Returns statement position which is the closest to
11470// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011471RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011472 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011473 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011474 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11475 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011477 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011478
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011479 if (code->kind() != Code::FUNCTION &&
11480 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011481 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011482 }
11483
11484 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011485 int closest_pc = 0;
11486 int distance = kMaxInt;
11487 while (!it.done()) {
11488 int statement_position = static_cast<int>(it.rinfo()->data());
11489 // Check if this break point is closer that what was previously found.
11490 if (source_position <= statement_position &&
11491 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011492 closest_pc =
11493 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011494 distance = statement_position - source_position;
11495 // Check whether we can't get any closer.
11496 if (distance == 0) break;
11497 }
11498 it.next();
11499 }
11500
11501 return Smi::FromInt(closest_pc);
11502}
11503
11504
ager@chromium.org357bf652010-04-12 11:30:10 +000011505// Calls specified function with or without entering the debugger.
11506// This is used in unit tests to run code as if debugger is entered or simply
11507// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011508RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011509 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011510 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011511 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11512 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11513
11514 Handle<Object> result;
11515 bool pending_exception;
11516 {
11517 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011518 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011519 &pending_exception);
11520 } else {
11521 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011522 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011523 &pending_exception);
11524 }
11525 }
11526 if (!pending_exception) {
11527 return *result;
11528 } else {
11529 return Failure::Exception();
11530 }
11531}
11532
11533
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011534// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011535RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011536 CONVERT_CHECKED(String, arg, args[0]);
11537 SmartPointer<char> flags =
11538 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11539 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011540 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011541}
11542
11543
11544// Performs a GC.
11545// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011546RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011547 isolate->heap()->CollectAllGarbage(true);
11548 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011549}
11550
11551
11552// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011553RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011554 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011555 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011556 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011557 }
11558 return Smi::FromInt(usage);
11559}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011560
11561
11562// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011563RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011564#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011565 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011566#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011567 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011568#endif
11569}
11570
11571
11572// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011573RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011574#ifdef LIVE_OBJECT_LIST
11575 return LiveObjectList::Capture();
11576#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011577 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011578#endif
11579}
11580
11581
11582// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011583RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011584#ifdef LIVE_OBJECT_LIST
11585 CONVERT_SMI_CHECKED(id, args[0]);
11586 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011587 return success ? isolate->heap()->true_value() :
11588 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011589#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011590 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011591#endif
11592}
11593
11594
11595// Generates the response to a debugger request for a dump of the objects
11596// contained in the difference between the captured live object lists
11597// specified by id1 and id2.
11598// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11599// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011600RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011601#ifdef LIVE_OBJECT_LIST
11602 HandleScope scope;
11603 CONVERT_SMI_CHECKED(id1, args[0]);
11604 CONVERT_SMI_CHECKED(id2, args[1]);
11605 CONVERT_SMI_CHECKED(start, args[2]);
11606 CONVERT_SMI_CHECKED(count, args[3]);
11607 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11608 EnterDebugger enter_debugger;
11609 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11610#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011611 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011612#endif
11613}
11614
11615
11616// Gets the specified object as requested by the debugger.
11617// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011618RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011619#ifdef LIVE_OBJECT_LIST
11620 CONVERT_SMI_CHECKED(obj_id, args[0]);
11621 Object* result = LiveObjectList::GetObj(obj_id);
11622 return result;
11623#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011624 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011625#endif
11626}
11627
11628
11629// Gets the obj id for the specified address if valid.
11630// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011631RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011632#ifdef LIVE_OBJECT_LIST
11633 HandleScope scope;
11634 CONVERT_ARG_CHECKED(String, address, 0);
11635 Object* result = LiveObjectList::GetObjId(address);
11636 return result;
11637#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011638 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011639#endif
11640}
11641
11642
11643// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011644RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011645#ifdef LIVE_OBJECT_LIST
11646 HandleScope scope;
11647 CONVERT_SMI_CHECKED(obj_id, args[0]);
11648 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11649 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11650 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11651 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11652 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11653
11654 Handle<JSObject> instance_filter;
11655 if (args[1]->IsJSObject()) {
11656 instance_filter = args.at<JSObject>(1);
11657 }
11658 bool verbose = false;
11659 if (args[2]->IsBoolean()) {
11660 verbose = args[2]->IsTrue();
11661 }
11662 int start = 0;
11663 if (args[3]->IsSmi()) {
11664 start = Smi::cast(args[3])->value();
11665 }
11666 int limit = Smi::kMaxValue;
11667 if (args[4]->IsSmi()) {
11668 limit = Smi::cast(args[4])->value();
11669 }
11670
11671 return LiveObjectList::GetObjRetainers(obj_id,
11672 instance_filter,
11673 verbose,
11674 start,
11675 limit,
11676 filter_obj);
11677#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011678 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011679#endif
11680}
11681
11682
11683// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011684RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011685#ifdef LIVE_OBJECT_LIST
11686 HandleScope scope;
11687 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11688 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11689 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11690
11691 Handle<JSObject> instance_filter;
11692 if (args[2]->IsJSObject()) {
11693 instance_filter = args.at<JSObject>(2);
11694 }
11695
11696 Object* result =
11697 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11698 return result;
11699#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011700 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011701#endif
11702}
11703
11704
11705// Generates the response to a debugger request for a list of all
11706// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011707RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011708#ifdef LIVE_OBJECT_LIST
11709 CONVERT_SMI_CHECKED(start, args[0]);
11710 CONVERT_SMI_CHECKED(count, args[1]);
11711 return LiveObjectList::Info(start, count);
11712#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011713 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011714#endif
11715}
11716
11717
11718// Gets a dump of the specified object as requested by the debugger.
11719// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011720RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011721#ifdef LIVE_OBJECT_LIST
11722 HandleScope scope;
11723 CONVERT_SMI_CHECKED(obj_id, args[0]);
11724 Object* result = LiveObjectList::PrintObj(obj_id);
11725 return result;
11726#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011727 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011728#endif
11729}
11730
11731
11732// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011733RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011734#ifdef LIVE_OBJECT_LIST
11735 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011736 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011737#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011738 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011739#endif
11740}
11741
11742
11743// Generates the response to a debugger request for a summary of the types
11744// of objects in the difference between the captured live object lists
11745// specified by id1 and id2.
11746// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11747// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011748RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011749#ifdef LIVE_OBJECT_LIST
11750 HandleScope scope;
11751 CONVERT_SMI_CHECKED(id1, args[0]);
11752 CONVERT_SMI_CHECKED(id2, args[1]);
11753 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11754
11755 EnterDebugger enter_debugger;
11756 return LiveObjectList::Summarize(id1, id2, filter_obj);
11757#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011758 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011759#endif
11760}
11761
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011762#endif // ENABLE_DEBUGGER_SUPPORT
11763
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011764
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011765#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011766RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011767 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011768 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011769
11770 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011771 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11772 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011773 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011774}
11775
11776
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011777RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011778 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011779 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011780
11781 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011782 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11783 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011784 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011785}
11786
11787#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011788
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011789// Finds the script object from the script data. NOTE: This operation uses
11790// heap traversal to find the function generated for the source position
11791// for the requested break point. For lazily compiled functions several heap
11792// traversals might be required rendering this operation as a rather slow
11793// operation. However for setting break points which is normally done through
11794// some kind of user interaction the performance is not crucial.
11795static Handle<Object> Runtime_GetScriptFromScriptName(
11796 Handle<String> script_name) {
11797 // Scan the heap for Script objects to find the script with the requested
11798 // script data.
11799 Handle<Script> script;
11800 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011801 HeapObject* obj = NULL;
11802 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011803 // If a script is found check if it has the script data requested.
11804 if (obj->IsScript()) {
11805 if (Script::cast(obj)->name()->IsString()) {
11806 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11807 script = Handle<Script>(Script::cast(obj));
11808 }
11809 }
11810 }
11811 }
11812
11813 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011814 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011815
11816 // Return the script found.
11817 return GetScriptWrapper(script);
11818}
11819
11820
11821// Get the script object from script data. NOTE: Regarding performance
11822// see the NOTE for GetScriptFromScriptData.
11823// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011824RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011825 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011826
11827 ASSERT(args.length() == 1);
11828
11829 CONVERT_CHECKED(String, script_name, args[0]);
11830
11831 // Find the requested script.
11832 Handle<Object> result =
11833 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11834 return *result;
11835}
11836
11837
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011838// Determines whether the given stack frame should be displayed in
11839// a stack trace. The caller is the error constructor that asked
11840// for the stack trace to be collected. The first time a construct
11841// call to this function is encountered it is skipped. The seen_caller
11842// in/out parameter is used to remember if the caller has been seen
11843// yet.
11844static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11845 bool* seen_caller) {
11846 // Only display JS frames.
11847 if (!raw_frame->is_java_script())
11848 return false;
11849 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11850 Object* raw_fun = frame->function();
11851 // Not sure when this can happen but skip it just in case.
11852 if (!raw_fun->IsJSFunction())
11853 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011854 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011855 *seen_caller = true;
11856 return false;
11857 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011858 // Skip all frames until we've seen the caller. Also, skip the most
11859 // obvious builtin calls. Some builtin calls (such as Number.ADD
11860 // which is invoked using 'call') are very difficult to recognize
11861 // so we're leaving them in for now.
11862 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011863}
11864
11865
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011866// Collect the raw data for a stack trace. Returns an array of 4
11867// element segments each containing a receiver, function, code and
11868// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011869RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011870 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011871 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011872 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11873
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011874 HandleScope scope(isolate);
11875 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011876
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011877 limit = Max(limit, 0); // Ensure that limit is not negative.
11878 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011879 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011880 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011881
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011882 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011883 // If the caller parameter is a function we skip frames until we're
11884 // under it before starting to collect.
11885 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011886 int cursor = 0;
11887 int frames_seen = 0;
11888 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011889 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011890 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011891 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011892 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011893 // Set initial size to the maximum inlining level + 1 for the outermost
11894 // function.
11895 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011896 frame->Summarize(&frames);
11897 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011898 if (cursor + 4 > elements->length()) {
11899 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11900 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011901 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011902 for (int i = 0; i < cursor; i++) {
11903 new_elements->set(i, elements->get(i));
11904 }
11905 elements = new_elements;
11906 }
11907 ASSERT(cursor + 4 <= elements->length());
11908
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011909 Handle<Object> recv = frames[i].receiver();
11910 Handle<JSFunction> fun = frames[i].function();
11911 Handle<Code> code = frames[i].code();
11912 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011913 elements->set(cursor++, *recv);
11914 elements->set(cursor++, *fun);
11915 elements->set(cursor++, *code);
11916 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011917 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011918 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011919 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011920 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011921 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011922 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011923 return *result;
11924}
11925
11926
ager@chromium.org3811b432009-10-28 14:53:37 +000011927// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011928RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011929 ASSERT_EQ(args.length(), 0);
11930
11931 NoHandleAllocation ha;
11932
11933 const char* version_string = v8::V8::GetVersion();
11934
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011935 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
11936 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000011937}
11938
11939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011940RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011941 ASSERT(args.length() == 2);
11942 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11943 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011944 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011945 OS::Abort();
11946 UNREACHABLE();
11947 return NULL;
11948}
11949
11950
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011951RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011952 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011953 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011954 Object* key = args[1];
11955
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011956 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011957 Object* o = cache->get(finger_index);
11958 if (o == key) {
11959 // The fastest case: hit the same place again.
11960 return cache->get(finger_index + 1);
11961 }
11962
11963 for (int i = finger_index - 2;
11964 i >= JSFunctionResultCache::kEntriesIndex;
11965 i -= 2) {
11966 o = cache->get(i);
11967 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011968 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011969 return cache->get(i + 1);
11970 }
11971 }
11972
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011973 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011974 ASSERT(size <= cache->length());
11975
11976 for (int i = size - 2; i > finger_index; i -= 2) {
11977 o = cache->get(i);
11978 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011979 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011980 return cache->get(i + 1);
11981 }
11982 }
11983
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011984 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011985 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011986
11987 Handle<JSFunctionResultCache> cache_handle(cache);
11988 Handle<Object> key_handle(key);
11989 Handle<Object> value;
11990 {
11991 Handle<JSFunction> factory(JSFunction::cast(
11992 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11993 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011994 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011995 // This handle is nor shared, nor used later, so it's safe.
11996 Object** argv[] = { key_handle.location() };
11997 bool pending_exception = false;
11998 value = Execution::Call(factory,
11999 receiver,
12000 1,
12001 argv,
12002 &pending_exception);
12003 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012004 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012005
12006#ifdef DEBUG
12007 cache_handle->JSFunctionResultCacheVerify();
12008#endif
12009
12010 // Function invocation may have cleared the cache. Reread all the data.
12011 finger_index = cache_handle->finger_index();
12012 size = cache_handle->size();
12013
12014 // If we have spare room, put new data into it, otherwise evict post finger
12015 // entry which is likely to be the least recently used.
12016 int index = -1;
12017 if (size < cache_handle->length()) {
12018 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12019 index = size;
12020 } else {
12021 index = finger_index + JSFunctionResultCache::kEntrySize;
12022 if (index == cache_handle->length()) {
12023 index = JSFunctionResultCache::kEntriesIndex;
12024 }
12025 }
12026
12027 ASSERT(index % 2 == 0);
12028 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12029 ASSERT(index < cache_handle->length());
12030
12031 cache_handle->set(index, *key_handle);
12032 cache_handle->set(index + 1, *value);
12033 cache_handle->set_finger_index(index);
12034
12035#ifdef DEBUG
12036 cache_handle->JSFunctionResultCacheVerify();
12037#endif
12038
12039 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012040}
12041
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012043RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012044 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012045 CONVERT_ARG_CHECKED(String, type, 0);
12046 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012047 return *isolate->factory()->NewJSMessageObject(
12048 type,
12049 arguments,
12050 0,
12051 0,
12052 isolate->factory()->undefined_value(),
12053 isolate->factory()->undefined_value(),
12054 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012055}
12056
12057
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012058RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012059 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12060 return message->type();
12061}
12062
12063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012064RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012065 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12066 return message->arguments();
12067}
12068
12069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012070RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012071 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12072 return Smi::FromInt(message->start_position());
12073}
12074
12075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012076RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012077 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12078 return message->script();
12079}
12080
12081
kasper.lund44510672008-07-25 07:37:58 +000012082#ifdef DEBUG
12083// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12084// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012085RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012086 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012087 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012088#define COUNT_ENTRY(Name, argc, ressize) + 1
12089 int entry_count = 0
12090 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12091 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12092 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12093#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012094 Factory* factory = isolate->factory();
12095 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012096 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012097 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012098#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012099 { \
12100 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012101 Handle<String> name; \
12102 /* Inline runtime functions have an underscore in front of the name. */ \
12103 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012104 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012105 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12106 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012107 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012108 Vector<const char>(#Name, StrLength(#Name))); \
12109 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012110 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012111 pair_elements->set(0, *name); \
12112 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012113 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012114 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012115 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012116 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012117 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012118 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012119 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012120 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012121#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012122 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012123 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012124 return *result;
12125}
kasper.lund44510672008-07-25 07:37:58 +000012126#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012127
12128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012129RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012130 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012131 CONVERT_CHECKED(String, format, args[0]);
12132 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012133 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012134 LOGGER->LogRuntime(chars, elms);
12135 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012136}
12137
12138
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012139RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012140 UNREACHABLE(); // implemented as macro in the parser
12141 return NULL;
12142}
12143
12144
12145// ----------------------------------------------------------------------------
12146// Implementation of Runtime
12147
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012148#define F(name, number_of_args, result_size) \
12149 { Runtime::k##name, Runtime::RUNTIME, #name, \
12150 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012151
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012152
12153#define I(name, number_of_args, result_size) \
12154 { Runtime::kInline##name, Runtime::INLINE, \
12155 "_" #name, NULL, number_of_args, result_size },
12156
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012157static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012158 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012159 INLINE_FUNCTION_LIST(I)
12160 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012161};
12162
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012163
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012164MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12165 Object* dictionary) {
12166 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012167 ASSERT(dictionary != NULL);
12168 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12169 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012170 Object* name_symbol;
12171 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012172 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012173 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12174 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012175 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012176 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12177 String::cast(name_symbol),
12178 Smi::FromInt(i),
12179 PropertyDetails(NONE, NORMAL));
12180 if (!maybe_dictionary->ToObject(&dictionary)) {
12181 // Non-recoverable failure. Calling code must restart heap
12182 // initialization.
12183 return maybe_dictionary;
12184 }
12185 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012186 }
12187 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012188}
12189
12190
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012191const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12192 Heap* heap = name->GetHeap();
12193 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012194 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012195 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012196 int function_index = Smi::cast(smi_index)->value();
12197 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012198 }
12199 return NULL;
12200}
12201
12202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012203const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012204 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12205}
12206
12207
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012208void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012209 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012210 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012211 if (failure->IsRetryAfterGC()) {
12212 // Try to do a garbage collection; ignore it if it fails. The C
12213 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012214 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012215 } else {
12216 // Handle last resort GC and make sure to allow future allocations
12217 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012218 isolate->counters()->gc_last_resort_from_js()->Increment();
12219 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012220 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012221}
12222
12223
12224} } // namespace v8::internal