blob: 922225f4d155db5c6e435840599528f01e2f6cfb [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"
danno@chromium.org40cb8782011-05-25 07:58:50 +000045#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000046#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000047#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000048#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000051#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000053#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000055#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000056#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058
kasperl@chromium.org71affb52009-05-26 05:44:31 +000059namespace v8 {
60namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
62
ager@chromium.org3e875802009-06-29 08:26:34 +000063#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000064 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66// Cast the given object to a value of the specified type and store
67// it in a variable with the given name. If the object is not of the
68// expected type call IllegalOperation and return.
69#define CONVERT_CHECKED(Type, name, obj) \
70 RUNTIME_ASSERT(obj->Is##Type()); \
71 Type* name = Type::cast(obj);
72
73#define CONVERT_ARG_CHECKED(Type, name, index) \
74 RUNTIME_ASSERT(args[index]->Is##Type()); \
75 Handle<Type> name = args.at<Type>(index);
76
kasper.lundbd3ec4e2008-07-09 11:06:54 +000077// Cast the given object to a boolean and store it in a variable with
78// the given name. If the object is not a boolean call IllegalOperation
79// and return.
80#define CONVERT_BOOLEAN_CHECKED(name, obj) \
81 RUNTIME_ASSERT(obj->IsBoolean()); \
82 bool name = (obj)->IsTrue();
83
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000084// Cast the given object to a Smi and store its value in an int variable
85// with the given name. If the object is not a Smi call IllegalOperation
86// and return.
87#define CONVERT_SMI_CHECKED(name, obj) \
88 RUNTIME_ASSERT(obj->IsSmi()); \
89 int name = Smi::cast(obj)->value();
90
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091// Cast the given object to a double and store it in a variable with
92// the given name. If the object is not a number (as opposed to
93// the number not-a-number) call IllegalOperation and return.
94#define CONVERT_DOUBLE_CHECKED(name, obj) \
95 RUNTIME_ASSERT(obj->IsNumber()); \
96 double name = (obj)->Number();
97
98// Call the specified converter on the object *comand store the result in
99// a variable of the specified type with the given name. If the
100// object is not a Number call IllegalOperation and return.
101#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
102 RUNTIME_ASSERT(obj->IsNumber()); \
103 type name = NumberTo##Type(obj);
104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000106MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
107 JSObject* boilerplate) {
108 StackLimitCheck check(isolate);
109 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000112 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000114 if (!maybe_result->ToObject(&result)) return maybe_result;
115 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000116 JSObject* copy = JSObject::cast(result);
117
118 // Deep copy local properties.
119 if (copy->HasFastProperties()) {
120 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000121 for (int i = 0; i < properties->length(); i++) {
122 Object* value = properties->get(i);
123 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000124 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000125 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000126 if (!maybe_result->ToObject(&result)) return maybe_result;
127 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000128 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000129 }
130 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000131 int nof = copy->map()->inobject_properties();
132 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000133 Object* value = copy->InObjectPropertyAt(i);
134 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000135 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000136 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000137 if (!maybe_result->ToObject(&result)) return maybe_result;
138 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000139 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 }
141 }
142 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000143 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000144 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 if (!maybe_result->ToObject(&result)) return maybe_result;
146 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000147 FixedArray* names = FixedArray::cast(result);
148 copy->GetLocalPropertyNames(names, 0);
149 for (int i = 0; i < names->length(); i++) {
150 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000152 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000153 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 // Only deep copy fields from the object literal expression.
155 // In particular, don't try to copy the length attribute of
156 // an array.
157 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 Object* value =
159 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000160 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000162 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000163 if (!maybe_result->ToObject(&result)) return maybe_result;
164 }
165 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000166 // Creating object copy for literals. No strict mode needed.
167 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000168 if (!maybe_result->ToObject(&result)) return maybe_result;
169 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000170 }
171 }
172 }
173
174 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000175 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000176 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000177 switch (copy->GetElementsKind()) {
178 case JSObject::FAST_ELEMENTS: {
179 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000180 if (elements->map() == heap->fixed_cow_array_map()) {
181 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000182#ifdef DEBUG
183 for (int i = 0; i < elements->length(); i++) {
184 ASSERT(!elements->get(i)->IsJSObject());
185 }
186#endif
187 } else {
188 for (int i = 0; i < elements->length(); i++) {
189 Object* value = elements->get(i);
190 if (value->IsJSObject()) {
191 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000192 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
193 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000194 if (!maybe_result->ToObject(&result)) return maybe_result;
195 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000196 elements->set(i, result);
197 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000198 }
199 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000200 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000201 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000202 case JSObject::DICTIONARY_ELEMENTS: {
203 NumberDictionary* element_dictionary = copy->element_dictionary();
204 int capacity = element_dictionary->Capacity();
205 for (int i = 0; i < capacity; i++) {
206 Object* k = element_dictionary->KeyAt(i);
207 if (element_dictionary->IsKey(k)) {
208 Object* value = element_dictionary->ValueAt(i);
209 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000210 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000211 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
212 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000213 if (!maybe_result->ToObject(&result)) return maybe_result;
214 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000215 element_dictionary->ValueAtPut(i, result);
216 }
217 }
218 }
219 break;
220 }
221 default:
222 UNREACHABLE();
223 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000224 }
225 return copy;
226}
227
228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000229RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000231 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000232}
233
234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000235RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000237 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238}
239
240
ager@chromium.org236ad962008-09-25 09:45:57 +0000241static Handle<Map> ComputeObjectLiteralMap(
242 Handle<Context> context,
243 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000244 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000245 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000246 int properties_length = constant_properties->length();
247 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000248 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000249 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000250 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000251 for (int p = 0; p != properties_length; p += 2) {
252 Object* key = constant_properties->get(p);
253 uint32_t element_index = 0;
254 if (key->IsSymbol()) {
255 number_of_symbol_keys++;
256 } else if (key->ToArrayIndex(&element_index)) {
257 // An index key does not require space in the property backing store.
258 number_of_properties--;
259 } else {
260 // Bail out as a non-symbol non-index key makes caching impossible.
261 // ASSERT to make sure that the if condition after the loop is false.
262 ASSERT(number_of_symbol_keys != number_of_properties);
263 break;
264 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000265 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000266 // If we only have symbols and array indices among keys then we can
267 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000268 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000269 if ((number_of_symbol_keys == number_of_properties) &&
270 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000271 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000272 Handle<FixedArray> keys =
273 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000274 if (number_of_symbol_keys > 0) {
275 int index = 0;
276 for (int p = 0; p < properties_length; p += 2) {
277 Object* key = constant_properties->get(p);
278 if (key->IsSymbol()) {
279 keys->set(index++, key);
280 }
281 }
282 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000283 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000284 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000285 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000286 }
287 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000288 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000289 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000290 Handle<Map>(context->object_function()->initial_map()),
291 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000292}
293
294
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000295static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000296 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000297 Handle<FixedArray> literals,
298 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000299
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000300
301static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000302 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000303 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000304 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000305 bool should_have_fast_elements,
306 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000307 // Get the global context from the literals array. This is the
308 // context in which the function was created and we use the object
309 // function from this context to create the object literal. We do
310 // not use the object function from the current global context
311 // because this might be the object function from another context
312 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000313 Handle<Context> context =
314 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
315
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000316 // In case we have function literals, we want the object to be in
317 // slow properties mode for now. We don't go in the map cache because
318 // maps with constant functions can't be shared if the functions are
319 // not the same (which is the common case).
320 bool is_result_from_cache = false;
321 Handle<Map> map = has_function_literal
322 ? Handle<Map>(context->object_function()->initial_map())
323 : ComputeObjectLiteralMap(context,
324 constant_properties,
325 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000326
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000327 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000328
329 // Normalize the elements of the boilerplate to save space if needed.
330 if (!should_have_fast_elements) NormalizeElements(boilerplate);
331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000332 // Add the constant properties to the boilerplate.
333 int length = constant_properties->length();
334 bool should_transform =
335 !is_result_from_cache && boilerplate->HasFastProperties();
336 if (should_transform || has_function_literal) {
337 // Normalize the properties of object to avoid n^2 behavior
338 // when extending the object multiple properties. Indicate the number of
339 // properties to be added.
340 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
341 }
342
343 for (int index = 0; index < length; index +=2) {
344 Handle<Object> key(constant_properties->get(index+0), isolate);
345 Handle<Object> value(constant_properties->get(index+1), isolate);
346 if (value->IsFixedArray()) {
347 // The value contains the constant_properties of a
348 // simple object or array literal.
349 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
350 value = CreateLiteralBoilerplate(isolate, literals, array);
351 if (value.is_null()) return value;
352 }
353 Handle<Object> result;
354 uint32_t element_index = 0;
355 if (key->IsSymbol()) {
356 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
357 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000358 result = SetOwnElement(boilerplate,
359 element_index,
360 value,
361 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000363 Handle<String> name(String::cast(*key));
364 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000365 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
366 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000368 } else if (key->ToArrayIndex(&element_index)) {
369 // Array index (uint32).
370 result = SetOwnElement(boilerplate,
371 element_index,
372 value,
373 kNonStrictMode);
374 } else {
375 // Non-uint32 number.
376 ASSERT(key->IsNumber());
377 double num = key->Number();
378 char arr[100];
379 Vector<char> buffer(arr, ARRAY_SIZE(arr));
380 const char* str = DoubleToCString(num, buffer);
381 Handle<String> name =
382 isolate->factory()->NewStringFromAscii(CStrVector(str));
383 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
384 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000385 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000386 // If setting the property on the boilerplate throws an
387 // exception, the exception is converted to an empty handle in
388 // the handle based operations. In that case, we need to
389 // convert back to an exception.
390 if (result.is_null()) return result;
391 }
392
393 // Transform to fast properties if necessary. For object literals with
394 // containing function literals we defer this operation until after all
395 // computed properties have been assigned so that we can generate
396 // constant function properties.
397 if (should_transform && !has_function_literal) {
398 TransformToFastProperties(boilerplate,
399 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 }
401
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000402 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000403}
404
405
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000407 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000408 Handle<FixedArray> literals,
409 Handle<FixedArray> elements) {
410 // Create the JSArray.
411 Handle<JSFunction> constructor(
412 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 const bool is_cow =
416 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000417 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000419
420 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000421 if (is_cow) {
422#ifdef DEBUG
423 // Copy-on-write arrays must be shallow (and simple).
424 for (int i = 0; i < content->length(); i++) {
425 ASSERT(!content->get(i)->IsFixedArray());
426 }
427#endif
428 } else {
429 for (int i = 0; i < content->length(); i++) {
430 if (content->get(i)->IsFixedArray()) {
431 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000433 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
434 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000436 if (result.is_null()) return result;
437 content->set(i, *result);
438 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000439 }
440 }
441
442 // Set the elements.
443 Handle<JSArray>::cast(object)->SetContent(*content);
444 return object;
445}
446
447
448static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000449 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000450 Handle<FixedArray> literals,
451 Handle<FixedArray> array) {
452 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000453 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000454 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000455 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000456 return CreateObjectLiteralBoilerplate(isolate,
457 literals,
458 elements,
459 true,
460 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000461 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462 return CreateObjectLiteralBoilerplate(isolate,
463 literals,
464 elements,
465 false,
466 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000468 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000469 default:
470 UNREACHABLE();
471 return Handle<Object>::null();
472 }
473}
474
475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000476RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000477 // Takes a FixedArray of elements containing the literal elements of
478 // the array literal and produces JSArray with those elements.
479 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000480 // which contains the context from which to get the Array function
481 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000482 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000483 ASSERT(args.length() == 3);
484 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
485 CONVERT_SMI_CHECKED(literals_index, args[1]);
486 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000488 Handle<Object> object =
489 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000490 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000492 // Update the functions literal and return the boilerplate.
493 literals->set(literals_index, *object);
494 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000495}
496
497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000498RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000499 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000500 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000501 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
502 CONVERT_SMI_CHECKED(literals_index, args[1]);
503 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000504 CONVERT_SMI_CHECKED(flags, args[3]);
505 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
506 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000507
508 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000509 Handle<Object> boilerplate(literals->get(literals_index), isolate);
510 if (*boilerplate == isolate->heap()->undefined_value()) {
511 boilerplate = CreateObjectLiteralBoilerplate(isolate,
512 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000513 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000514 should_have_fast_elements,
515 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000516 if (boilerplate.is_null()) return Failure::Exception();
517 // Update the functions literal and return the boilerplate.
518 literals->set(literals_index, *boilerplate);
519 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000520 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000521}
522
523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000524RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000526 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000527 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
528 CONVERT_SMI_CHECKED(literals_index, args[1]);
529 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000530 CONVERT_SMI_CHECKED(flags, args[3]);
531 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
532 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000533
534 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000535 Handle<Object> boilerplate(literals->get(literals_index), isolate);
536 if (*boilerplate == isolate->heap()->undefined_value()) {
537 boilerplate = CreateObjectLiteralBoilerplate(isolate,
538 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000539 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 should_have_fast_elements,
541 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000542 if (boilerplate.is_null()) return Failure::Exception();
543 // Update the functions literal and return the boilerplate.
544 literals->set(literals_index, *boilerplate);
545 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000547}
548
549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000550RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000552 ASSERT(args.length() == 3);
553 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
554 CONVERT_SMI_CHECKED(literals_index, args[1]);
555 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
556
557 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000558 Handle<Object> boilerplate(literals->get(literals_index), isolate);
559 if (*boilerplate == isolate->heap()->undefined_value()) {
560 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000561 if (boilerplate.is_null()) return Failure::Exception();
562 // Update the functions literal and return the boilerplate.
563 literals->set(literals_index, *boilerplate);
564 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000566}
567
568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000569RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000570 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000571 ASSERT(args.length() == 3);
572 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
573 CONVERT_SMI_CHECKED(literals_index, args[1]);
574 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
575
576 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 Handle<Object> boilerplate(literals->get(literals_index), isolate);
578 if (*boilerplate == isolate->heap()->undefined_value()) {
579 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580 if (boilerplate.is_null()) return Failure::Exception();
581 // Update the functions literal and return the boilerplate.
582 literals->set(literals_index, *boilerplate);
583 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000584 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000585 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000586 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000588 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589}
590
591
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000592RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
593 ASSERT(args.length() == 2);
594 Object* handler = args[0];
595 Object* prototype = args[1];
596 Object* used_prototype =
597 (prototype->IsJSObject() || prototype->IsJSProxy()) ? prototype
598 : isolate->heap()->null_value();
599 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
600}
601
602
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000603RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000604 ASSERT(args.length() == 2);
605 CONVERT_CHECKED(String, key, args[0]);
606 Object* value = args[1];
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000607 ASSERT(!value->IsFailure());
ager@chromium.org32912102009-01-16 10:38:43 +0000608 // Create a catch context extension object.
609 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000610 isolate->context()->global_context()->
611 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000612 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000613 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000614 if (!maybe_object->ToObject(&object)) return maybe_object;
615 }
ager@chromium.org32912102009-01-16 10:38:43 +0000616 // Assign the exception value to the catch variable and make sure
617 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000618 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000619 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
620 JSObject::cast(object)->SetProperty(
621 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000622 if (!maybe_value->ToObject(&value)) return maybe_value;
623 }
ager@chromium.org32912102009-01-16 10:38:43 +0000624 return object;
625}
626
627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000628RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000629 NoHandleAllocation ha;
630 ASSERT(args.length() == 1);
631 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000632 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633 return JSObject::cast(obj)->class_name();
634}
635
ager@chromium.org7c537e22008-10-16 08:43:32 +0000636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000637RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638 NoHandleAllocation ha;
639 ASSERT(args.length() == 2);
640 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
641 Object* O = args[0];
642 Object* V = args[1];
643 while (true) {
644 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000645 if (prototype->IsNull()) return isolate->heap()->false_value();
646 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000647 V = prototype;
648 }
649}
650
651
ager@chromium.org9085a012009-05-11 19:22:57 +0000652// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000653RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000654 NoHandleAllocation ha;
655 ASSERT(args.length() == 2);
656 CONVERT_CHECKED(JSObject, jsobject, args[0]);
657 CONVERT_CHECKED(JSObject, proto, args[1]);
658
659 // Sanity checks. The old prototype (that we are replacing) could
660 // theoretically be null, but if it is not null then check that we
661 // didn't already install a hidden prototype here.
662 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
663 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
664 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
665
666 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000667 Object* map_or_failure;
668 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
669 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
670 return maybe_map_or_failure;
671 }
672 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000673 Map* new_proto_map = Map::cast(map_or_failure);
674
lrn@chromium.org303ada72010-10-27 09:33:13 +0000675 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
676 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
677 return maybe_map_or_failure;
678 }
679 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000680 Map* new_map = Map::cast(map_or_failure);
681
682 // Set proto's prototype to be the old prototype of the object.
683 new_proto_map->set_prototype(jsobject->GetPrototype());
684 proto->set_map(new_proto_map);
685 new_proto_map->set_is_hidden_prototype();
686
687 // Set the object's prototype to proto.
688 new_map->set_prototype(proto);
689 jsobject->set_map(new_map);
690
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000691 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000692}
693
694
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000695RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000697 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000698 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000699 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000700}
701
702
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000703// Recursively traverses hidden prototypes if property is not found
704static void GetOwnPropertyImplementation(JSObject* obj,
705 String* name,
706 LookupResult* result) {
707 obj->LocalLookupRealNamedProperty(name, result);
708
709 if (!result->IsProperty()) {
710 Object* proto = obj->GetPrototype();
711 if (proto->IsJSObject() &&
712 JSObject::cast(proto)->map()->is_hidden_prototype())
713 GetOwnPropertyImplementation(JSObject::cast(proto),
714 name, result);
715 }
716}
717
718
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000719static bool CheckAccessException(LookupResult* result,
720 v8::AccessType access_type) {
721 if (result->type() == CALLBACKS) {
722 Object* callback = result->GetCallbackObject();
723 if (callback->IsAccessorInfo()) {
724 AccessorInfo* info = AccessorInfo::cast(callback);
725 bool can_access =
726 (access_type == v8::ACCESS_HAS &&
727 (info->all_can_read() || info->all_can_write())) ||
728 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
729 (access_type == v8::ACCESS_SET && info->all_can_write());
730 return can_access;
731 }
732 }
733
734 return false;
735}
736
737
738static bool CheckAccess(JSObject* obj,
739 String* name,
740 LookupResult* result,
741 v8::AccessType access_type) {
742 ASSERT(result->IsProperty());
743
744 JSObject* holder = result->holder();
745 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000746 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000747 while (true) {
748 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000749 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000750 // Access check callback denied the access, but some properties
751 // can have a special permissions which override callbacks descision
752 // (currently see v8::AccessControl).
753 break;
754 }
755
756 if (current == holder) {
757 return true;
758 }
759
760 current = JSObject::cast(current->GetPrototype());
761 }
762
763 // API callbacks can have per callback access exceptions.
764 switch (result->type()) {
765 case CALLBACKS: {
766 if (CheckAccessException(result, access_type)) {
767 return true;
768 }
769 break;
770 }
771 case INTERCEPTOR: {
772 // If the object has an interceptor, try real named properties.
773 // Overwrite the result to fetch the correct property later.
774 holder->LookupRealNamedProperty(name, result);
775 if (result->IsProperty()) {
776 if (CheckAccessException(result, access_type)) {
777 return true;
778 }
779 }
780 break;
781 }
782 default:
783 break;
784 }
785
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000786 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000787 return false;
788}
789
790
791// TODO(1095): we should traverse hidden prototype hierachy as well.
792static bool CheckElementAccess(JSObject* obj,
793 uint32_t index,
794 v8::AccessType access_type) {
795 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000796 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000797 return false;
798 }
799
800 return true;
801}
802
803
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000804// Enumerator used as indices into the array returned from GetOwnProperty
805enum PropertyDescriptorIndices {
806 IS_ACCESSOR_INDEX,
807 VALUE_INDEX,
808 GETTER_INDEX,
809 SETTER_INDEX,
810 WRITABLE_INDEX,
811 ENUMERABLE_INDEX,
812 CONFIGURABLE_INDEX,
813 DESCRIPTOR_SIZE
814};
815
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000816// Returns an array with the property description:
817// if args[1] is not a property on args[0]
818// returns undefined
819// if args[1] is a data property on args[0]
820// [false, value, Writeable, Enumerable, Configurable]
821// if args[1] is an accessor on args[0]
822// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000823RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000824 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000825 Heap* heap = isolate->heap();
826 HandleScope scope(isolate);
827 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
828 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000829 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000830 CONVERT_ARG_CHECKED(JSObject, obj, 0);
831 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000832
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000833 // This could be an element.
834 uint32_t index;
835 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000836 switch (obj->HasLocalElement(index)) {
837 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000838 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000839
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000840 case JSObject::STRING_CHARACTER_ELEMENT: {
841 // Special handling of string objects according to ECMAScript 5
842 // 15.5.5.2. Note that this might be a string object with elements
843 // other than the actual string value. This is covered by the
844 // subsequent cases.
845 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
846 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000847 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000848
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000849 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000850 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000851 elms->set(WRITABLE_INDEX, heap->false_value());
852 elms->set(ENUMERABLE_INDEX, heap->false_value());
853 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000854 return *desc;
855 }
856
857 case JSObject::INTERCEPTED_ELEMENT:
858 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000860 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000862 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000863 elms->set(WRITABLE_INDEX, heap->true_value());
864 elms->set(ENUMERABLE_INDEX, heap->true_value());
865 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000866 return *desc;
867 }
868
869 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000870 Handle<JSObject> holder = obj;
871 if (obj->IsJSGlobalProxy()) {
872 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000873 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000874 ASSERT(proto->IsJSGlobalObject());
875 holder = Handle<JSObject>(JSObject::cast(proto));
876 }
877 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000878 int entry = dictionary->FindEntry(index);
879 ASSERT(entry != NumberDictionary::kNotFound);
880 PropertyDetails details = dictionary->DetailsAt(entry);
881 switch (details.type()) {
882 case CALLBACKS: {
883 // This is an accessor property with getter and/or setter.
884 FixedArray* callbacks =
885 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000886 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000887 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
888 elms->set(GETTER_INDEX, callbacks->get(0));
889 }
890 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
891 elms->set(SETTER_INDEX, callbacks->get(1));
892 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000893 break;
894 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000895 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000896 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000897 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000898 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000899 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000900 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000901 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000902 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000903 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000904 default:
905 UNREACHABLE();
906 break;
907 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000908 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
909 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000910 return *desc;
911 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000912 }
913 }
914
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000915 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000916 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000917
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000918 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000919 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000920 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000921
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000922 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000923 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000924 }
925
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000926 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
927 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000928
929 bool is_js_accessor = (result.type() == CALLBACKS) &&
930 (result.GetCallbackObject()->IsFixedArray());
931
932 if (is_js_accessor) {
933 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000934 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000935
936 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
937 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
938 elms->set(GETTER_INDEX, structure->get(0));
939 }
940 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
941 elms->set(SETTER_INDEX, structure->get(1));
942 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000943 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000944 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
945 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000946
947 PropertyAttributes attrs;
948 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000949 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000950 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
951 if (!maybe_value->ToObject(&value)) return maybe_value;
952 }
953 elms->set(VALUE_INDEX, value);
954 }
955
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000956 return *desc;
957}
958
959
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000960RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000961 ASSERT(args.length() == 1);
962 CONVERT_CHECKED(JSObject, obj, args[0]);
963 return obj->PreventExtensions();
964}
965
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000967RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000968 ASSERT(args.length() == 1);
969 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000970 if (obj->IsJSGlobalProxy()) {
971 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000972 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000973 ASSERT(proto->IsJSGlobalObject());
974 obj = JSObject::cast(proto);
975 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000976 return obj->map()->is_extensible() ? isolate->heap()->true_value()
977 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000978}
979
980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000981RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000982 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000983 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000984 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
985 CONVERT_ARG_CHECKED(String, pattern, 1);
986 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000987 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
988 if (result.is_null()) return Failure::Exception();
989 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000990}
991
992
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000993RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000995 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000996 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000997 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998}
999
1000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001001RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002 ASSERT(args.length() == 1);
1003 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001004 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001005 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006}
1007
1008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001009RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 ASSERT(args.length() == 2);
1011 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001013 int index = field->value();
1014 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1015 InstanceType type = templ->map()->instance_type();
1016 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1017 type == OBJECT_TEMPLATE_INFO_TYPE);
1018 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001019 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001020 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1021 } else {
1022 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1023 }
1024 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001025}
1026
1027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001028RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001029 ASSERT(args.length() == 1);
1030 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001031 Map* old_map = object->map();
1032 bool needs_access_checks = old_map->is_access_check_needed();
1033 if (needs_access_checks) {
1034 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001035 Object* new_map;
1036 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1037 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1038 }
ager@chromium.org32912102009-01-16 10:38:43 +00001039
1040 Map::cast(new_map)->set_is_access_check_needed(false);
1041 object->set_map(Map::cast(new_map));
1042 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001043 return needs_access_checks ? isolate->heap()->true_value()
1044 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001045}
1046
1047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001048RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001049 ASSERT(args.length() == 1);
1050 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001051 Map* old_map = object->map();
1052 if (!old_map->is_access_check_needed()) {
1053 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001054 Object* new_map;
1055 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1056 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1057 }
ager@chromium.org32912102009-01-16 10:38:43 +00001058
1059 Map::cast(new_map)->set_is_access_check_needed(true);
1060 object->set_map(Map::cast(new_map));
1061 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001062 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001063}
1064
1065
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001066static Failure* ThrowRedeclarationError(Isolate* isolate,
1067 const char* type,
1068 Handle<String> name) {
1069 HandleScope scope(isolate);
1070 Handle<Object> type_handle =
1071 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001072 Handle<Object> args[2] = { type_handle, name };
1073 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001074 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1075 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001076}
1077
1078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001079RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001080 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001081 HandleScope scope(isolate);
1082 Handle<GlobalObject> global = Handle<GlobalObject>(
1083 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084
ager@chromium.org3811b432009-10-28 14:53:37 +00001085 Handle<Context> context = args.at<Context>(0);
1086 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001087 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001088 StrictModeFlag strict_mode =
1089 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1090 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091
1092 // Compute the property attributes. According to ECMA-262, section
1093 // 13, page 71, the property must be read-only and
1094 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1095 // property as read-only, so we don't either.
1096 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1097
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098 // Traverse the name/value pairs and set the properties.
1099 int length = pairs->length();
1100 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001101 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001103 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001104
1105 // We have to declare a global const property. To capture we only
1106 // assign to it when evaluating the assignment for "const x =
1107 // <expr>" the initial value is the hole.
1108 bool is_const_property = value->IsTheHole();
1109
1110 if (value->IsUndefined() || is_const_property) {
1111 // Lookup the property in the global object, and don't set the
1112 // value of the variable if the property is already there.
1113 LookupResult lookup;
1114 global->Lookup(*name, &lookup);
1115 if (lookup.IsProperty()) {
1116 // Determine if the property is local by comparing the holder
1117 // against the global object. The information will be used to
1118 // avoid throwing re-declaration errors when declaring
1119 // variables or constants that exist in the prototype chain.
1120 bool is_local = (*global == lookup.holder());
1121 // Get the property attributes and determine if the property is
1122 // read-only.
1123 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1124 bool is_read_only = (attributes & READ_ONLY) != 0;
1125 if (lookup.type() == INTERCEPTOR) {
1126 // If the interceptor says the property is there, we
1127 // just return undefined without overwriting the property.
1128 // Otherwise, we continue to setting the property.
1129 if (attributes != ABSENT) {
1130 // Check if the existing property conflicts with regards to const.
1131 if (is_local && (is_read_only || is_const_property)) {
1132 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001133 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134 };
1135 // The property already exists without conflicting: Go to
1136 // the next declaration.
1137 continue;
1138 }
1139 // Fall-through and introduce the absent property by using
1140 // SetProperty.
1141 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001142 // For const properties, we treat a callback with this name
1143 // even in the prototype as a conflicting declaration.
1144 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001145 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001146 }
1147 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148 if (is_local && (is_read_only || is_const_property)) {
1149 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001150 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 }
1152 // The property already exists without conflicting: Go to
1153 // the next declaration.
1154 continue;
1155 }
1156 }
1157 } else {
1158 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001159 Handle<SharedFunctionInfo> shared =
1160 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001162 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1163 context,
1164 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165 value = function;
1166 }
1167
1168 LookupResult lookup;
1169 global->LocalLookup(*name, &lookup);
1170
1171 PropertyAttributes attributes = is_const_property
1172 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1173 : base;
1174
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001175 // There's a local property that we need to overwrite because
1176 // we're either declaring a function or there's an interceptor
1177 // that claims the property is absent.
1178 //
1179 // Check for conflicting re-declarations. We cannot have
1180 // conflicting types in case of intercepted properties because
1181 // they are absent.
1182 if (lookup.IsProperty() &&
1183 (lookup.type() != INTERCEPTOR) &&
1184 (lookup.IsReadOnly() || is_const_property)) {
1185 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001186 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001187 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001189 // Safari does not allow the invocation of callback setters for
1190 // function declarations. To mimic this behavior, we do not allow
1191 // the invocation of setters for function values. This makes a
1192 // difference for global functions with the same names as event
1193 // handlers such as "function onload() {}". Firefox does call the
1194 // onload setter in those case and Safari does not. We follow
1195 // Safari for compatibility.
1196 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001197 // Do not change DONT_DELETE to false from true.
1198 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1199 attributes = static_cast<PropertyAttributes>(
1200 attributes | (lookup.GetAttributes() & DONT_DELETE));
1201 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001202 RETURN_IF_EMPTY_HANDLE(isolate,
1203 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001204 name,
1205 value,
1206 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001207 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001208 RETURN_IF_EMPTY_HANDLE(isolate,
1209 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001210 name,
1211 value,
1212 attributes,
1213 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 }
1215 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001216
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001217 ASSERT(!isolate->has_pending_exception());
1218 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219}
1220
1221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001222RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001223 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001224 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001225
ager@chromium.org7c537e22008-10-16 08:43:32 +00001226 CONVERT_ARG_CHECKED(Context, context, 0);
1227 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001228 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001229 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001230 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001231 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232
1233 // Declarations are always done in the function context.
1234 context = Handle<Context>(context->fcontext());
1235
1236 int index;
1237 PropertyAttributes attributes;
1238 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001239 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240 context->Lookup(name, flags, &index, &attributes);
1241
1242 if (attributes != ABSENT) {
1243 // The name was declared before; check for conflicting
1244 // re-declarations: This is similar to the code in parser.cc in
1245 // the AstBuildingParser::Declare function.
1246 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1247 // Functions are not read-only.
1248 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1249 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001250 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251 }
1252
1253 // Initialize it if necessary.
1254 if (*initial_value != NULL) {
1255 if (index >= 0) {
1256 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001257 // the function context or the arguments object.
1258 if (holder->IsContext()) {
1259 ASSERT(holder.is_identical_to(context));
1260 if (((attributes & READ_ONLY) == 0) ||
1261 context->get(index)->IsTheHole()) {
1262 context->set(index, *initial_value);
1263 }
1264 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001265 // The holder is an arguments object.
1266 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001267 Handle<Object> result = SetElement(arguments, index, initial_value,
1268 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001269 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270 }
1271 } else {
1272 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001273 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001274 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001275 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001276 SetProperty(context_ext, name, initial_value,
1277 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 }
1279 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001282 // The property is not in the function context. It needs to be
1283 // "declared" in the function context's extension context, or in the
1284 // global context.
1285 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001286 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001287 // The function context's extension context exists - use it.
1288 context_ext = Handle<JSObject>(context->extension());
1289 } else {
1290 // The function context's extension context does not exists - allocate
1291 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001292 context_ext = isolate->factory()->NewJSObject(
1293 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001294 // And store it in the extension slot.
1295 context->set_extension(*context_ext);
1296 }
1297 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298
ager@chromium.org7c537e22008-10-16 08:43:32 +00001299 // Declare the property by setting it to the initial value if provided,
1300 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1301 // constant declarations).
1302 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001303 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001304 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001305 // Declaring a const context slot is a conflicting declaration if
1306 // there is a callback with that name in a prototype. It is
1307 // allowed to introduce const variables in
1308 // JSContextExtensionObjects. They are treated specially in
1309 // SetProperty and no setters are invoked for those since they are
1310 // not real JSObjects.
1311 if (initial_value->IsTheHole() &&
1312 !context_ext->IsJSContextExtensionObject()) {
1313 LookupResult lookup;
1314 context_ext->Lookup(*name, &lookup);
1315 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001316 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001317 }
1318 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001319 RETURN_IF_EMPTY_HANDLE(isolate,
1320 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001321 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001322 }
1323
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001324 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325}
1326
1327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001328RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001330 // args[0] == name
1331 // args[1] == strict_mode
1332 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333
1334 // Determine if we need to assign to the variable if it already
1335 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001336 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1337 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338
1339 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001340 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001341 RUNTIME_ASSERT(args[1]->IsSmi());
1342 StrictModeFlag strict_mode =
1343 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1344 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345
1346 // According to ECMA-262, section 12.2, page 62, the property must
1347 // not be deletable.
1348 PropertyAttributes attributes = DONT_DELETE;
1349
1350 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001351 // there, there is a property with this name in the prototype chain.
1352 // We follow Safari and Firefox behavior and only set the property
1353 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001354 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001355 // Note that objects can have hidden prototypes, so we need to traverse
1356 // the whole chain of hidden prototypes to do a 'local' lookup.
1357 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001359 while (true) {
1360 real_holder->LocalLookup(*name, &lookup);
1361 if (lookup.IsProperty()) {
1362 // Determine if this is a redeclaration of something read-only.
1363 if (lookup.IsReadOnly()) {
1364 // If we found readonly property on one of hidden prototypes,
1365 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001366 if (real_holder != isolate->context()->global()) break;
1367 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001368 }
1369
1370 // Determine if this is a redeclaration of an intercepted read-only
1371 // property and figure out if the property exists at all.
1372 bool found = true;
1373 PropertyType type = lookup.type();
1374 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001375 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001376 Handle<JSObject> holder(real_holder);
1377 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1378 real_holder = *holder;
1379 if (intercepted == ABSENT) {
1380 // The interceptor claims the property isn't there. We need to
1381 // make sure to introduce it.
1382 found = false;
1383 } else if ((intercepted & READ_ONLY) != 0) {
1384 // The property is present, but read-only. Since we're trying to
1385 // overwrite it with a variable declaration we must throw a
1386 // re-declaration error. However if we found readonly property
1387 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001388 if (real_holder != isolate->context()->global()) break;
1389 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001390 }
1391 }
1392
1393 if (found && !assign) {
1394 // The global property is there and we're not assigning any value
1395 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001396 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001397 }
1398
1399 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001400 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001401 return real_holder->SetProperty(
1402 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001403 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001404
1405 Object* proto = real_holder->GetPrototype();
1406 if (!proto->IsJSObject())
1407 break;
1408
1409 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1410 break;
1411
1412 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413 }
1414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001415 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001416 if (assign) {
1417 return global->SetProperty(*name, args[2], attributes, strict_mode);
1418 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001419 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420}
1421
1422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001423RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424 // All constants are declared with an initial value. The name
1425 // of the constant is the first argument and the initial value
1426 // is the second.
1427 RUNTIME_ASSERT(args.length() == 2);
1428 CONVERT_ARG_CHECKED(String, name, 0);
1429 Handle<Object> value = args.at<Object>(1);
1430
1431 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001432 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433
1434 // According to ECMA-262, section 12.2, page 62, the property must
1435 // not be deletable. Since it's a const, it must be READ_ONLY too.
1436 PropertyAttributes attributes =
1437 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1438
1439 // Lookup the property locally in the global object. If it isn't
1440 // there, we add the property and take special precautions to always
1441 // add it as a local property even in case of callbacks in the
1442 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001443 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 LookupResult lookup;
1445 global->LocalLookup(*name, &lookup);
1446 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001447 return global->SetLocalPropertyIgnoreAttributes(*name,
1448 *value,
1449 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001450 }
1451
1452 // Determine if this is a redeclaration of something not
1453 // read-only. In case the result is hidden behind an interceptor we
1454 // need to ask it for the property attributes.
1455 if (!lookup.IsReadOnly()) {
1456 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458 }
1459
1460 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1461
1462 // Throw re-declaration error if the intercepted property is present
1463 // but not read-only.
1464 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001465 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466 }
1467
1468 // Restore global object from context (in case of GC) and continue
1469 // with setting the value because the property is either absent or
1470 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001471 HandleScope handle_scope(isolate);
1472 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001474 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475 // property through an interceptor and only do it if it's
1476 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001477 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001478 RETURN_IF_EMPTY_HANDLE(isolate,
1479 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001480 name,
1481 value,
1482 attributes,
1483 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484 return *value;
1485 }
1486
1487 // Set the value, but only we're assigning the initial value to a
1488 // constant. For now, we determine this by checking if the
1489 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001490 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001491 PropertyType type = lookup.type();
1492 if (type == FIELD) {
1493 FixedArray* properties = global->properties();
1494 int index = lookup.GetFieldIndex();
1495 if (properties->get(index)->IsTheHole()) {
1496 properties->set(index, *value);
1497 }
1498 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001499 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1500 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 }
1502 } else {
1503 // Ignore re-initialization of constants that have already been
1504 // assigned a function value.
1505 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1506 }
1507
1508 // Use the set value as the result of the operation.
1509 return *value;
1510}
1511
1512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001513RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001514 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 ASSERT(args.length() == 3);
1516
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001517 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001518 ASSERT(!value->IsTheHole());
1519 CONVERT_ARG_CHECKED(Context, context, 1);
1520 Handle<String> name(String::cast(args[2]));
1521
1522 // Initializations are always done in the function context.
1523 context = Handle<Context>(context->fcontext());
1524
1525 int index;
1526 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001527 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001528 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529 context->Lookup(name, flags, &index, &attributes);
1530
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001531 // In most situations, the property introduced by the const
1532 // declaration should be present in the context extension object.
1533 // However, because declaration and initialization are separate, the
1534 // property might have been deleted (if it was introduced by eval)
1535 // before we reach the initialization point.
1536 //
1537 // Example:
1538 //
1539 // function f() { eval("delete x; const x;"); }
1540 //
1541 // In that case, the initialization behaves like a normal assignment
1542 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001544 // Property was found in a context.
1545 if (holder->IsContext()) {
1546 // The holder cannot be the function context. If it is, there
1547 // should have been a const redeclaration error when declaring
1548 // the const property.
1549 ASSERT(!holder.is_identical_to(context));
1550 if ((attributes & READ_ONLY) == 0) {
1551 Handle<Context>::cast(holder)->set(index, *value);
1552 }
1553 } else {
1554 // The holder is an arguments object.
1555 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001556 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001557 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001558 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001559 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 }
1561 return *value;
1562 }
1563
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001564 // The property could not be found, we introduce it in the global
1565 // context.
1566 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001567 Handle<JSObject> global = Handle<JSObject>(
1568 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001569 // Strict mode not needed (const disallowed in strict mode).
1570 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001571 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001572 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001573 return *value;
1574 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001575
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001576 // The property was present in a context extension object.
1577 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001579 if (*context_ext == context->extension()) {
1580 // This is the property that was introduced by the const
1581 // declaration. Set it if it hasn't been set before. NOTE: We
1582 // cannot use GetProperty() to get the current value as it
1583 // 'unholes' the value.
1584 LookupResult lookup;
1585 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1586 ASSERT(lookup.IsProperty()); // the property was declared
1587 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1588
1589 PropertyType type = lookup.type();
1590 if (type == FIELD) {
1591 FixedArray* properties = context_ext->properties();
1592 int index = lookup.GetFieldIndex();
1593 if (properties->get(index)->IsTheHole()) {
1594 properties->set(index, *value);
1595 }
1596 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001597 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1598 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001599 }
1600 } else {
1601 // We should not reach here. Any real, named property should be
1602 // either a field or a dictionary slot.
1603 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001604 }
1605 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001606 // The property was found in a different context extension object.
1607 // Set it if it is not a read-only property.
1608 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001609 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001610 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001611 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001612 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001613 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001614 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001616 return *value;
1617}
1618
1619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001620RUNTIME_FUNCTION(MaybeObject*,
1621 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001622 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001623 ASSERT(args.length() == 2);
1624 CONVERT_ARG_CHECKED(JSObject, object, 0);
1625 CONVERT_SMI_CHECKED(properties, args[1]);
1626 if (object->HasFastProperties()) {
1627 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1628 }
1629 return *object;
1630}
1631
1632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001633RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001634 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001635 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001636 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1637 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001638 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001639 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001640 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001641 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001642 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001643 RUNTIME_ASSERT(index >= 0);
1644 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001646 Handle<Object> result = RegExpImpl::Exec(regexp,
1647 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001648 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001649 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001650 if (result.is_null()) return Failure::Exception();
1651 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001652}
1653
1654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001655RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001656 ASSERT(args.length() == 3);
1657 CONVERT_SMI_CHECKED(elements_count, args[0]);
1658 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001659 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001660 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001661 Object* new_object;
1662 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001663 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001664 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1665 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001666 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001667 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1668 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001669 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1670 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001671 {
1672 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001673 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001674 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001675 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001676 }
1677 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001678 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001679 array->set_elements(elements);
1680 array->set_length(Smi::FromInt(elements_count));
1681 // Write in-object properties after the length of the array.
1682 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1683 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1684 return array;
1685}
1686
1687
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001688RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001689 AssertNoAllocation no_alloc;
1690 ASSERT(args.length() == 5);
1691 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1692 CONVERT_CHECKED(String, source, args[1]);
1693
1694 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001695 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001696
1697 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001698 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001699
1700 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001701 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001702
1703 Map* map = regexp->map();
1704 Object* constructor = map->constructor();
1705 if (constructor->IsJSFunction() &&
1706 JSFunction::cast(constructor)->initial_map() == map) {
1707 // If we still have the original map, set in-object properties directly.
1708 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1709 // TODO(lrn): Consider skipping write barrier on booleans as well.
1710 // Both true and false should be in oldspace at all times.
1711 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1712 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1713 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1714 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1715 Smi::FromInt(0),
1716 SKIP_WRITE_BARRIER);
1717 return regexp;
1718 }
1719
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001720 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001721 PropertyAttributes final =
1722 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1723 PropertyAttributes writable =
1724 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001725 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001726 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001727 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001728 source,
1729 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001730 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001732 global,
1733 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001734 ASSERT(!result->IsFailure());
1735 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001736 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001737 ignoreCase,
1738 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001739 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001741 multiline,
1742 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001743 ASSERT(!result->IsFailure());
1744 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001745 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001746 Smi::FromInt(0),
1747 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001748 ASSERT(!result->IsFailure());
1749 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001750 return regexp;
1751}
1752
1753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001754RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001756 ASSERT(args.length() == 1);
1757 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1758 // This is necessary to enable fast checks for absence of elements
1759 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001760 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001761 return Smi::FromInt(0);
1762}
1763
1764
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001765static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1766 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001767 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001768 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001769 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1770 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1771 Handle<JSFunction> optimized =
1772 isolate->factory()->NewFunction(key,
1773 JS_OBJECT_TYPE,
1774 JSObject::kHeaderSize,
1775 code,
1776 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001777 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001778 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001779 return optimized;
1780}
1781
1782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001783RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001784 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001785 ASSERT(args.length() == 1);
1786 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1787
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001788 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1789 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1790 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1791 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1792 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1793 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1794 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001795
1796 return *holder;
1797}
1798
1799
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001800RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001801 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001802 Context* global_context =
1803 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001804 return global_context->global()->global_receiver();
1805}
1806
1807
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001808RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001810 ASSERT(args.length() == 4);
1811 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1812 int index = Smi::cast(args[1])->value();
1813 Handle<String> pattern = args.at<String>(2);
1814 Handle<String> flags = args.at<String>(3);
1815
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001816 // Get the RegExp function from the context in the literals array.
1817 // This is the RegExp function from the context in which the
1818 // function was created. We do not use the RegExp function from the
1819 // current global context because this might be the RegExp function
1820 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001821 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001822 Handle<JSFunction>(
1823 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001824 // Compute the regular expression literal.
1825 bool has_pending_exception;
1826 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001827 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1828 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001829 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001830 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001831 return Failure::Exception();
1832 }
1833 literals->set(index, *regexp);
1834 return *regexp;
1835}
1836
1837
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001838RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001839 NoHandleAllocation ha;
1840 ASSERT(args.length() == 1);
1841
1842 CONVERT_CHECKED(JSFunction, f, args[0]);
1843 return f->shared()->name();
1844}
1845
1846
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001847RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001848 NoHandleAllocation ha;
1849 ASSERT(args.length() == 2);
1850
1851 CONVERT_CHECKED(JSFunction, f, args[0]);
1852 CONVERT_CHECKED(String, name, args[1]);
1853 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001854 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001855}
1856
1857
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001858RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001859 NoHandleAllocation ha;
1860 ASSERT(args.length() == 1);
1861
1862 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001863 Object* obj = f->RemovePrototype();
1864 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001865
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001866 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001867}
1868
1869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001870RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001871 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001872 ASSERT(args.length() == 1);
1873
1874 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001875 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1876 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001877
1878 return *GetScriptWrapper(Handle<Script>::cast(script));
1879}
1880
1881
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001882RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001883 NoHandleAllocation ha;
1884 ASSERT(args.length() == 1);
1885
1886 CONVERT_CHECKED(JSFunction, f, args[0]);
1887 return f->shared()->GetSourceCode();
1888}
1889
1890
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001891RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001892 NoHandleAllocation ha;
1893 ASSERT(args.length() == 1);
1894
1895 CONVERT_CHECKED(JSFunction, fun, args[0]);
1896 int pos = fun->shared()->start_position();
1897 return Smi::FromInt(pos);
1898}
1899
1900
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001901RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001902 ASSERT(args.length() == 2);
1903
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001904 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001905 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1906
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001907 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1908
1909 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001910 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001911}
1912
1913
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001914RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001915 NoHandleAllocation ha;
1916 ASSERT(args.length() == 2);
1917
1918 CONVERT_CHECKED(JSFunction, fun, args[0]);
1919 CONVERT_CHECKED(String, name, args[1]);
1920 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001921 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001922}
1923
1924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001925RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 NoHandleAllocation ha;
1927 ASSERT(args.length() == 2);
1928
1929 CONVERT_CHECKED(JSFunction, fun, args[0]);
1930 CONVERT_CHECKED(Smi, length, args[1]);
1931 fun->shared()->set_length(length->value());
1932 return length;
1933}
1934
1935
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001936RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001937 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001938 ASSERT(args.length() == 2);
1939
1940 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001941 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001942 Object* obj;
1943 { MaybeObject* maybe_obj =
1944 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1945 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1946 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001947 return args[0]; // return TOS
1948}
1949
1950
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001951RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001952 NoHandleAllocation ha;
1953 ASSERT(args.length() == 1);
1954
1955 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001956 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1957 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001958}
1959
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001960
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001961RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001962 NoHandleAllocation ha;
1963 ASSERT(args.length() == 1);
1964
1965 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001966 return f->IsBuiltin() ? isolate->heap()->true_value() :
1967 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001968}
1969
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001970
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001971RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001972 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001973 ASSERT(args.length() == 2);
1974
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001975 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001976 Handle<Object> code = args.at<Object>(1);
1977
1978 Handle<Context> context(target->context());
1979
1980 if (!code->IsNull()) {
1981 RUNTIME_ASSERT(code->IsJSFunction());
1982 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001983 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001984
1985 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001986 return Failure::Exception();
1987 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001988 // Since we don't store the source for this we should never
1989 // optimize this.
1990 shared->code()->set_optimizable(false);
1991
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001992 // Set the code, scope info, formal parameter count,
1993 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001994 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001995 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001996 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001997 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001998 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001999 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002000 // Set the source code of the target function to undefined.
2001 // SetCode is only used for built-in constructors like String,
2002 // Array, and Object, and some web code
2003 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002004 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002005 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002006 // Clear the optimization hints related to the compiled code as these are no
2007 // longer valid when the code is overwritten.
2008 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002009 context = Handle<Context>(fun->context());
2010
2011 // Make sure we get a fresh copy of the literal vector to avoid
2012 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002013 int number_of_literals = fun->NumberOfLiterals();
2014 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002015 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002016 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002017 // Insert the object, regexp and array functions in the literals
2018 // array prefix. These are the functions that will be used when
2019 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002020 literals->set(JSFunction::kLiteralGlobalContextIndex,
2021 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002022 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002023 // It's okay to skip the write barrier here because the literals
2024 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002025 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002026 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002027 }
2028
2029 target->set_context(*context);
2030 return *target;
2031}
2032
2033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002034RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002035 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002036 ASSERT(args.length() == 2);
2037 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2038 CONVERT_SMI_CHECKED(num, args[1]);
2039 RUNTIME_ASSERT(num >= 0);
2040 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002041 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002042}
2043
2044
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002045MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2046 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002047 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002048 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002049 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002051 }
2052 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002053 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002054}
2055
2056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002057RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002058 NoHandleAllocation ha;
2059 ASSERT(args.length() == 2);
2060
2061 CONVERT_CHECKED(String, subject, args[0]);
2062 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002063 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002064
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002065 uint32_t i = 0;
2066 if (index->IsSmi()) {
2067 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002068 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002069 i = value;
2070 } else {
2071 ASSERT(index->IsHeapNumber());
2072 double value = HeapNumber::cast(index)->value();
2073 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002074 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002075
2076 // Flatten the string. If someone wants to get a char at an index
2077 // in a cons string, it is likely that more indices will be
2078 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002079 Object* flat;
2080 { MaybeObject* maybe_flat = subject->TryFlatten();
2081 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2082 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002083 subject = String::cast(flat);
2084
2085 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002086 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002087 }
2088
2089 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002090}
2091
2092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002093RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002094 NoHandleAllocation ha;
2095 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002096 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002097}
2098
lrn@chromium.org25156de2010-04-06 13:10:27 +00002099
2100class FixedArrayBuilder {
2101 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002102 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2103 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002104 length_(0) {
2105 // Require a non-zero initial size. Ensures that doubling the size to
2106 // extend the array will work.
2107 ASSERT(initial_capacity > 0);
2108 }
2109
2110 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2111 : array_(backing_store),
2112 length_(0) {
2113 // Require a non-zero initial size. Ensures that doubling the size to
2114 // extend the array will work.
2115 ASSERT(backing_store->length() > 0);
2116 }
2117
2118 bool HasCapacity(int elements) {
2119 int length = array_->length();
2120 int required_length = length_ + elements;
2121 return (length >= required_length);
2122 }
2123
2124 void EnsureCapacity(int elements) {
2125 int length = array_->length();
2126 int required_length = length_ + elements;
2127 if (length < required_length) {
2128 int new_length = length;
2129 do {
2130 new_length *= 2;
2131 } while (new_length < required_length);
2132 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002133 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002134 array_->CopyTo(0, *extended_array, 0, length_);
2135 array_ = extended_array;
2136 }
2137 }
2138
2139 void Add(Object* value) {
2140 ASSERT(length_ < capacity());
2141 array_->set(length_, value);
2142 length_++;
2143 }
2144
2145 void Add(Smi* value) {
2146 ASSERT(length_ < capacity());
2147 array_->set(length_, value);
2148 length_++;
2149 }
2150
2151 Handle<FixedArray> array() {
2152 return array_;
2153 }
2154
2155 int length() {
2156 return length_;
2157 }
2158
2159 int capacity() {
2160 return array_->length();
2161 }
2162
2163 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002164 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002165 result_array->set_length(Smi::FromInt(length_));
2166 return result_array;
2167 }
2168
2169 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2170 target_array->set_elements(*array_);
2171 target_array->set_length(Smi::FromInt(length_));
2172 return target_array;
2173 }
2174
2175 private:
2176 Handle<FixedArray> array_;
2177 int length_;
2178};
2179
2180
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002181// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002182const int kStringBuilderConcatHelperLengthBits = 11;
2183const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002184
2185template <typename schar>
2186static inline void StringBuilderConcatHelper(String*,
2187 schar*,
2188 FixedArray*,
2189 int);
2190
lrn@chromium.org25156de2010-04-06 13:10:27 +00002191typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2192 StringBuilderSubstringLength;
2193typedef BitField<int,
2194 kStringBuilderConcatHelperLengthBits,
2195 kStringBuilderConcatHelperPositionBits>
2196 StringBuilderSubstringPosition;
2197
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002198
2199class ReplacementStringBuilder {
2200 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002201 ReplacementStringBuilder(Heap* heap,
2202 Handle<String> subject,
2203 int estimated_part_count)
2204 : heap_(heap),
2205 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002206 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002207 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002208 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002209 // Require a non-zero initial size. Ensures that doubling the size to
2210 // extend the array will work.
2211 ASSERT(estimated_part_count > 0);
2212 }
2213
lrn@chromium.org25156de2010-04-06 13:10:27 +00002214 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2215 int from,
2216 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002217 ASSERT(from >= 0);
2218 int length = to - from;
2219 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002220 if (StringBuilderSubstringLength::is_valid(length) &&
2221 StringBuilderSubstringPosition::is_valid(from)) {
2222 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2223 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002224 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002225 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002226 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002227 builder->Add(Smi::FromInt(-length));
2228 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002229 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002230 }
2231
2232
2233 void EnsureCapacity(int elements) {
2234 array_builder_.EnsureCapacity(elements);
2235 }
2236
2237
2238 void AddSubjectSlice(int from, int to) {
2239 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002240 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002241 }
2242
2243
2244 void AddString(Handle<String> string) {
2245 int length = string->length();
2246 ASSERT(length > 0);
2247 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002248 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002249 is_ascii_ = false;
2250 }
2251 IncrementCharacterCount(length);
2252 }
2253
2254
2255 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002256 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002257 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002258 }
2259
2260 Handle<String> joined_string;
2261 if (is_ascii_) {
2262 joined_string = NewRawAsciiString(character_count_);
2263 AssertNoAllocation no_alloc;
2264 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2265 char* char_buffer = seq->GetChars();
2266 StringBuilderConcatHelper(*subject_,
2267 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002268 *array_builder_.array(),
2269 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002270 } else {
2271 // Non-ASCII.
2272 joined_string = NewRawTwoByteString(character_count_);
2273 AssertNoAllocation no_alloc;
2274 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2275 uc16* char_buffer = seq->GetChars();
2276 StringBuilderConcatHelper(*subject_,
2277 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002278 *array_builder_.array(),
2279 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002280 }
2281 return joined_string;
2282 }
2283
2284
2285 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002286 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002287 V8::FatalProcessOutOfMemory("String.replace result too large.");
2288 }
2289 character_count_ += by;
2290 }
2291
lrn@chromium.org25156de2010-04-06 13:10:27 +00002292 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002293 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002294 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002295
lrn@chromium.org25156de2010-04-06 13:10:27 +00002296 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002297 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002298 CALL_HEAP_FUNCTION(heap_->isolate(),
2299 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002300 }
2301
2302
2303 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002304 CALL_HEAP_FUNCTION(heap_->isolate(),
2305 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002306 }
2307
2308
2309 void AddElement(Object* element) {
2310 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002311 ASSERT(array_builder_.capacity() > array_builder_.length());
2312 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002313 }
2314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002315 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002316 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002317 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002318 int character_count_;
2319 bool is_ascii_;
2320};
2321
2322
2323class CompiledReplacement {
2324 public:
2325 CompiledReplacement()
2326 : parts_(1), replacement_substrings_(0) {}
2327
2328 void Compile(Handle<String> replacement,
2329 int capture_count,
2330 int subject_length);
2331
2332 void Apply(ReplacementStringBuilder* builder,
2333 int match_from,
2334 int match_to,
2335 Handle<JSArray> last_match_info);
2336
2337 // Number of distinct parts of the replacement pattern.
2338 int parts() {
2339 return parts_.length();
2340 }
2341 private:
2342 enum PartType {
2343 SUBJECT_PREFIX = 1,
2344 SUBJECT_SUFFIX,
2345 SUBJECT_CAPTURE,
2346 REPLACEMENT_SUBSTRING,
2347 REPLACEMENT_STRING,
2348
2349 NUMBER_OF_PART_TYPES
2350 };
2351
2352 struct ReplacementPart {
2353 static inline ReplacementPart SubjectMatch() {
2354 return ReplacementPart(SUBJECT_CAPTURE, 0);
2355 }
2356 static inline ReplacementPart SubjectCapture(int capture_index) {
2357 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2358 }
2359 static inline ReplacementPart SubjectPrefix() {
2360 return ReplacementPart(SUBJECT_PREFIX, 0);
2361 }
2362 static inline ReplacementPart SubjectSuffix(int subject_length) {
2363 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2364 }
2365 static inline ReplacementPart ReplacementString() {
2366 return ReplacementPart(REPLACEMENT_STRING, 0);
2367 }
2368 static inline ReplacementPart ReplacementSubString(int from, int to) {
2369 ASSERT(from >= 0);
2370 ASSERT(to > from);
2371 return ReplacementPart(-from, to);
2372 }
2373
2374 // If tag <= 0 then it is the negation of a start index of a substring of
2375 // the replacement pattern, otherwise it's a value from PartType.
2376 ReplacementPart(int tag, int data)
2377 : tag(tag), data(data) {
2378 // Must be non-positive or a PartType value.
2379 ASSERT(tag < NUMBER_OF_PART_TYPES);
2380 }
2381 // Either a value of PartType or a non-positive number that is
2382 // the negation of an index into the replacement string.
2383 int tag;
2384 // The data value's interpretation depends on the value of tag:
2385 // tag == SUBJECT_PREFIX ||
2386 // tag == SUBJECT_SUFFIX: data is unused.
2387 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2388 // tag == REPLACEMENT_SUBSTRING ||
2389 // tag == REPLACEMENT_STRING: data is index into array of substrings
2390 // of the replacement string.
2391 // tag <= 0: Temporary representation of the substring of the replacement
2392 // string ranging over -tag .. data.
2393 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2394 // substring objects.
2395 int data;
2396 };
2397
2398 template<typename Char>
2399 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2400 Vector<Char> characters,
2401 int capture_count,
2402 int subject_length) {
2403 int length = characters.length();
2404 int last = 0;
2405 for (int i = 0; i < length; i++) {
2406 Char c = characters[i];
2407 if (c == '$') {
2408 int next_index = i + 1;
2409 if (next_index == length) { // No next character!
2410 break;
2411 }
2412 Char c2 = characters[next_index];
2413 switch (c2) {
2414 case '$':
2415 if (i > last) {
2416 // There is a substring before. Include the first "$".
2417 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2418 last = next_index + 1; // Continue after the second "$".
2419 } else {
2420 // Let the next substring start with the second "$".
2421 last = next_index;
2422 }
2423 i = next_index;
2424 break;
2425 case '`':
2426 if (i > last) {
2427 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2428 }
2429 parts->Add(ReplacementPart::SubjectPrefix());
2430 i = next_index;
2431 last = i + 1;
2432 break;
2433 case '\'':
2434 if (i > last) {
2435 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2436 }
2437 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2438 i = next_index;
2439 last = i + 1;
2440 break;
2441 case '&':
2442 if (i > last) {
2443 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2444 }
2445 parts->Add(ReplacementPart::SubjectMatch());
2446 i = next_index;
2447 last = i + 1;
2448 break;
2449 case '0':
2450 case '1':
2451 case '2':
2452 case '3':
2453 case '4':
2454 case '5':
2455 case '6':
2456 case '7':
2457 case '8':
2458 case '9': {
2459 int capture_ref = c2 - '0';
2460 if (capture_ref > capture_count) {
2461 i = next_index;
2462 continue;
2463 }
2464 int second_digit_index = next_index + 1;
2465 if (second_digit_index < length) {
2466 // Peek ahead to see if we have two digits.
2467 Char c3 = characters[second_digit_index];
2468 if ('0' <= c3 && c3 <= '9') { // Double digits.
2469 int double_digit_ref = capture_ref * 10 + c3 - '0';
2470 if (double_digit_ref <= capture_count) {
2471 next_index = second_digit_index;
2472 capture_ref = double_digit_ref;
2473 }
2474 }
2475 }
2476 if (capture_ref > 0) {
2477 if (i > last) {
2478 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2479 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002480 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002481 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2482 last = next_index + 1;
2483 }
2484 i = next_index;
2485 break;
2486 }
2487 default:
2488 i = next_index;
2489 break;
2490 }
2491 }
2492 }
2493 if (length > last) {
2494 if (last == 0) {
2495 parts->Add(ReplacementPart::ReplacementString());
2496 } else {
2497 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2498 }
2499 }
2500 }
2501
2502 ZoneList<ReplacementPart> parts_;
2503 ZoneList<Handle<String> > replacement_substrings_;
2504};
2505
2506
2507void CompiledReplacement::Compile(Handle<String> replacement,
2508 int capture_count,
2509 int subject_length) {
2510 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002511 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002512 AssertNoAllocation no_alloc;
2513 ParseReplacementPattern(&parts_,
2514 replacement->ToAsciiVector(),
2515 capture_count,
2516 subject_length);
2517 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002518 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002519 AssertNoAllocation no_alloc;
2520
2521 ParseReplacementPattern(&parts_,
2522 replacement->ToUC16Vector(),
2523 capture_count,
2524 subject_length);
2525 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002526 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002527 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002528 int substring_index = 0;
2529 for (int i = 0, n = parts_.length(); i < n; i++) {
2530 int tag = parts_[i].tag;
2531 if (tag <= 0) { // A replacement string slice.
2532 int from = -tag;
2533 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002534 replacement_substrings_.Add(
2535 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002536 parts_[i].tag = REPLACEMENT_SUBSTRING;
2537 parts_[i].data = substring_index;
2538 substring_index++;
2539 } else if (tag == REPLACEMENT_STRING) {
2540 replacement_substrings_.Add(replacement);
2541 parts_[i].data = substring_index;
2542 substring_index++;
2543 }
2544 }
2545}
2546
2547
2548void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2549 int match_from,
2550 int match_to,
2551 Handle<JSArray> last_match_info) {
2552 for (int i = 0, n = parts_.length(); i < n; i++) {
2553 ReplacementPart part = parts_[i];
2554 switch (part.tag) {
2555 case SUBJECT_PREFIX:
2556 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2557 break;
2558 case SUBJECT_SUFFIX: {
2559 int subject_length = part.data;
2560 if (match_to < subject_length) {
2561 builder->AddSubjectSlice(match_to, subject_length);
2562 }
2563 break;
2564 }
2565 case SUBJECT_CAPTURE: {
2566 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002567 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002568 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2569 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2570 if (from >= 0 && to > from) {
2571 builder->AddSubjectSlice(from, to);
2572 }
2573 break;
2574 }
2575 case REPLACEMENT_SUBSTRING:
2576 case REPLACEMENT_STRING:
2577 builder->AddString(replacement_substrings_[part.data]);
2578 break;
2579 default:
2580 UNREACHABLE();
2581 }
2582 }
2583}
2584
2585
2586
lrn@chromium.org303ada72010-10-27 09:33:13 +00002587MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002588 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002589 String* subject,
2590 JSRegExp* regexp,
2591 String* replacement,
2592 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002593 ASSERT(subject->IsFlat());
2594 ASSERT(replacement->IsFlat());
2595
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002596 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002597
2598 int length = subject->length();
2599 Handle<String> subject_handle(subject);
2600 Handle<JSRegExp> regexp_handle(regexp);
2601 Handle<String> replacement_handle(replacement);
2602 Handle<JSArray> last_match_info_handle(last_match_info);
2603 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2604 subject_handle,
2605 0,
2606 last_match_info_handle);
2607 if (match.is_null()) {
2608 return Failure::Exception();
2609 }
2610 if (match->IsNull()) {
2611 return *subject_handle;
2612 }
2613
2614 int capture_count = regexp_handle->CaptureCount();
2615
2616 // CompiledReplacement uses zone allocation.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002617 CompilationZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002618 CompiledReplacement compiled_replacement;
2619 compiled_replacement.Compile(replacement_handle,
2620 capture_count,
2621 length);
2622
2623 bool is_global = regexp_handle->GetFlags().is_global();
2624
2625 // Guessing the number of parts that the final result string is built
2626 // from. Global regexps can match any number of times, so we guess
2627 // conservatively.
2628 int expected_parts =
2629 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002630 ReplacementStringBuilder builder(isolate->heap(),
2631 subject_handle,
2632 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002633
2634 // Index of end of last match.
2635 int prev = 0;
2636
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002637 // Number of parts added by compiled replacement plus preceeding
2638 // string and possibly suffix after last match. It is possible for
2639 // all components to use two elements when encoded as two smis.
2640 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002641 bool matched = true;
2642 do {
2643 ASSERT(last_match_info_handle->HasFastElements());
2644 // Increase the capacity of the builder before entering local handle-scope,
2645 // so its internal buffer can safely allocate a new handle if it grows.
2646 builder.EnsureCapacity(parts_added_per_loop);
2647
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002648 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002649 int start, end;
2650 {
2651 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002652 FixedArray* match_info_array =
2653 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002654
2655 ASSERT_EQ(capture_count * 2 + 2,
2656 RegExpImpl::GetLastCaptureCount(match_info_array));
2657 start = RegExpImpl::GetCapture(match_info_array, 0);
2658 end = RegExpImpl::GetCapture(match_info_array, 1);
2659 }
2660
2661 if (prev < start) {
2662 builder.AddSubjectSlice(prev, start);
2663 }
2664 compiled_replacement.Apply(&builder,
2665 start,
2666 end,
2667 last_match_info_handle);
2668 prev = end;
2669
2670 // Only continue checking for global regexps.
2671 if (!is_global) break;
2672
2673 // Continue from where the match ended, unless it was an empty match.
2674 int next = end;
2675 if (start == end) {
2676 next = end + 1;
2677 if (next > length) break;
2678 }
2679
2680 match = RegExpImpl::Exec(regexp_handle,
2681 subject_handle,
2682 next,
2683 last_match_info_handle);
2684 if (match.is_null()) {
2685 return Failure::Exception();
2686 }
2687 matched = !match->IsNull();
2688 } while (matched);
2689
2690 if (prev < length) {
2691 builder.AddSubjectSlice(prev, length);
2692 }
2693
2694 return *(builder.ToString());
2695}
2696
2697
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002698template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002699MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002700 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002701 String* subject,
2702 JSRegExp* regexp,
2703 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002704 ASSERT(subject->IsFlat());
2705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002706 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002707
2708 Handle<String> subject_handle(subject);
2709 Handle<JSRegExp> regexp_handle(regexp);
2710 Handle<JSArray> last_match_info_handle(last_match_info);
2711 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2712 subject_handle,
2713 0,
2714 last_match_info_handle);
2715 if (match.is_null()) return Failure::Exception();
2716 if (match->IsNull()) return *subject_handle;
2717
2718 ASSERT(last_match_info_handle->HasFastElements());
2719
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002720 int start, end;
2721 {
2722 AssertNoAllocation match_info_array_is_not_in_a_handle;
2723 FixedArray* match_info_array =
2724 FixedArray::cast(last_match_info_handle->elements());
2725
2726 start = RegExpImpl::GetCapture(match_info_array, 0);
2727 end = RegExpImpl::GetCapture(match_info_array, 1);
2728 }
2729
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002730 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002731 int new_length = length - (end - start);
2732 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002733 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002734 }
2735 Handle<ResultSeqString> answer;
2736 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002737 answer = Handle<ResultSeqString>::cast(
2738 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002739 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002740 answer = Handle<ResultSeqString>::cast(
2741 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002742 }
2743
2744 // If the regexp isn't global, only match once.
2745 if (!regexp_handle->GetFlags().is_global()) {
2746 if (start > 0) {
2747 String::WriteToFlat(*subject_handle,
2748 answer->GetChars(),
2749 0,
2750 start);
2751 }
2752 if (end < length) {
2753 String::WriteToFlat(*subject_handle,
2754 answer->GetChars() + start,
2755 end,
2756 length);
2757 }
2758 return *answer;
2759 }
2760
2761 int prev = 0; // Index of end of last match.
2762 int next = 0; // Start of next search (prev unless last match was empty).
2763 int position = 0;
2764
2765 do {
2766 if (prev < start) {
2767 // Add substring subject[prev;start] to answer string.
2768 String::WriteToFlat(*subject_handle,
2769 answer->GetChars() + position,
2770 prev,
2771 start);
2772 position += start - prev;
2773 }
2774 prev = end;
2775 next = end;
2776 // Continue from where the match ended, unless it was an empty match.
2777 if (start == end) {
2778 next++;
2779 if (next > length) break;
2780 }
2781 match = RegExpImpl::Exec(regexp_handle,
2782 subject_handle,
2783 next,
2784 last_match_info_handle);
2785 if (match.is_null()) return Failure::Exception();
2786 if (match->IsNull()) break;
2787
2788 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002789 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002790 {
2791 AssertNoAllocation match_info_array_is_not_in_a_handle;
2792 FixedArray* match_info_array =
2793 FixedArray::cast(last_match_info_handle->elements());
2794 start = RegExpImpl::GetCapture(match_info_array, 0);
2795 end = RegExpImpl::GetCapture(match_info_array, 1);
2796 }
2797 } while (true);
2798
2799 if (prev < length) {
2800 // Add substring subject[prev;length] to answer string.
2801 String::WriteToFlat(*subject_handle,
2802 answer->GetChars() + position,
2803 prev,
2804 length);
2805 position += length - prev;
2806 }
2807
2808 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002809 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002810 }
2811
2812 // Shorten string and fill
2813 int string_size = ResultSeqString::SizeFor(position);
2814 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2815 int delta = allocated_string_size - string_size;
2816
2817 answer->set_length(position);
2818 if (delta == 0) return *answer;
2819
2820 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002821 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002822
2823 return *answer;
2824}
2825
2826
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002827RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002828 ASSERT(args.length() == 4);
2829
2830 CONVERT_CHECKED(String, subject, args[0]);
2831 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002832 Object* flat_subject;
2833 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2834 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2835 return maybe_flat_subject;
2836 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002837 }
2838 subject = String::cast(flat_subject);
2839 }
2840
2841 CONVERT_CHECKED(String, replacement, args[2]);
2842 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002843 Object* flat_replacement;
2844 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2845 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2846 return maybe_flat_replacement;
2847 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002848 }
2849 replacement = String::cast(flat_replacement);
2850 }
2851
2852 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2853 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2854
2855 ASSERT(last_match_info->HasFastElements());
2856
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002857 if (replacement->length() == 0) {
2858 if (subject->HasOnlyAsciiChars()) {
2859 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002860 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002861 } else {
2862 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002863 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002864 }
2865 }
2866
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002867 return StringReplaceRegExpWithString(isolate,
2868 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002869 regexp,
2870 replacement,
2871 last_match_info);
2872}
2873
2874
ager@chromium.org7c537e22008-10-16 08:43:32 +00002875// Perform string match of pattern on subject, starting at start index.
2876// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002877// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002878int Runtime::StringMatch(Isolate* isolate,
2879 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002880 Handle<String> pat,
2881 int start_index) {
2882 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002883 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002884
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002885 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002886 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002887
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002888 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002889 if (start_index + pattern_length > subject_length) return -1;
2890
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002891 if (!sub->IsFlat()) FlattenString(sub);
2892 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002893
ager@chromium.org7c537e22008-10-16 08:43:32 +00002894 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002895 // Extract flattened substrings of cons strings before determining asciiness.
2896 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002897 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002898 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002899 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002900
ager@chromium.org7c537e22008-10-16 08:43:32 +00002901 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002902 if (seq_pat->IsAsciiRepresentation()) {
2903 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2904 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002905 return SearchString(isolate,
2906 seq_sub->ToAsciiVector(),
2907 pat_vector,
2908 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002909 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002910 return SearchString(isolate,
2911 seq_sub->ToUC16Vector(),
2912 pat_vector,
2913 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002914 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002915 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2916 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002917 return SearchString(isolate,
2918 seq_sub->ToAsciiVector(),
2919 pat_vector,
2920 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002921 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002922 return SearchString(isolate,
2923 seq_sub->ToUC16Vector(),
2924 pat_vector,
2925 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002926}
2927
2928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002929RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002930 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002931 ASSERT(args.length() == 3);
2932
ager@chromium.org7c537e22008-10-16 08:43:32 +00002933 CONVERT_ARG_CHECKED(String, sub, 0);
2934 CONVERT_ARG_CHECKED(String, pat, 1);
2935
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002936 Object* index = args[2];
2937 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002938 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002939
ager@chromium.org870a0b62008-11-04 11:43:05 +00002940 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002941 int position =
2942 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002943 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002944}
2945
2946
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002947template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002948static int StringMatchBackwards(Vector<const schar> subject,
2949 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002950 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002951 int pattern_length = pattern.length();
2952 ASSERT(pattern_length >= 1);
2953 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002954
2955 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002956 for (int i = 0; i < pattern_length; i++) {
2957 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002958 if (c > String::kMaxAsciiCharCode) {
2959 return -1;
2960 }
2961 }
2962 }
2963
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002964 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002965 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002966 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002967 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002968 while (j < pattern_length) {
2969 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002970 break;
2971 }
2972 j++;
2973 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002974 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002975 return i;
2976 }
2977 }
2978 return -1;
2979}
2980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002981RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002982 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002983 ASSERT(args.length() == 3);
2984
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002985 CONVERT_ARG_CHECKED(String, sub, 0);
2986 CONVERT_ARG_CHECKED(String, pat, 1);
2987
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002988 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002989 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002990 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002991
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002992 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002993 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002994
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002995 if (start_index + pat_length > sub_length) {
2996 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002998
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002999 if (pat_length == 0) {
3000 return Smi::FromInt(start_index);
3001 }
3002
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003003 if (!sub->IsFlat()) FlattenString(sub);
3004 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003005
3006 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3007
3008 int position = -1;
3009
3010 if (pat->IsAsciiRepresentation()) {
3011 Vector<const char> pat_vector = pat->ToAsciiVector();
3012 if (sub->IsAsciiRepresentation()) {
3013 position = StringMatchBackwards(sub->ToAsciiVector(),
3014 pat_vector,
3015 start_index);
3016 } else {
3017 position = StringMatchBackwards(sub->ToUC16Vector(),
3018 pat_vector,
3019 start_index);
3020 }
3021 } else {
3022 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3023 if (sub->IsAsciiRepresentation()) {
3024 position = StringMatchBackwards(sub->ToAsciiVector(),
3025 pat_vector,
3026 start_index);
3027 } else {
3028 position = StringMatchBackwards(sub->ToUC16Vector(),
3029 pat_vector,
3030 start_index);
3031 }
3032 }
3033
3034 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003035}
3036
3037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003038RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003039 NoHandleAllocation ha;
3040 ASSERT(args.length() == 2);
3041
3042 CONVERT_CHECKED(String, str1, args[0]);
3043 CONVERT_CHECKED(String, str2, args[1]);
3044
3045 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003046 int str1_length = str1->length();
3047 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003048
3049 // Decide trivial cases without flattening.
3050 if (str1_length == 0) {
3051 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3052 return Smi::FromInt(-str2_length);
3053 } else {
3054 if (str2_length == 0) return Smi::FromInt(str1_length);
3055 }
3056
3057 int end = str1_length < str2_length ? str1_length : str2_length;
3058
3059 // No need to flatten if we are going to find the answer on the first
3060 // character. At this point we know there is at least one character
3061 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003062 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003063 if (d != 0) return Smi::FromInt(d);
3064
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003065 str1->TryFlatten();
3066 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003067
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003068 StringInputBuffer& buf1 =
3069 *isolate->runtime_state()->string_locale_compare_buf1();
3070 StringInputBuffer& buf2 =
3071 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003072
3073 buf1.Reset(str1);
3074 buf2.Reset(str2);
3075
3076 for (int i = 0; i < end; i++) {
3077 uint16_t char1 = buf1.GetNext();
3078 uint16_t char2 = buf2.GetNext();
3079 if (char1 != char2) return Smi::FromInt(char1 - char2);
3080 }
3081
3082 return Smi::FromInt(str1_length - str2_length);
3083}
3084
3085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003086RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003087 NoHandleAllocation ha;
3088 ASSERT(args.length() == 3);
3089
3090 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003091 Object* from = args[1];
3092 Object* to = args[2];
3093 int start, end;
3094 // We have a fast integer-only case here to avoid a conversion to double in
3095 // the common case where from and to are Smis.
3096 if (from->IsSmi() && to->IsSmi()) {
3097 start = Smi::cast(from)->value();
3098 end = Smi::cast(to)->value();
3099 } else {
3100 CONVERT_DOUBLE_CHECKED(from_number, from);
3101 CONVERT_DOUBLE_CHECKED(to_number, to);
3102 start = FastD2I(from_number);
3103 end = FastD2I(to_number);
3104 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003105 RUNTIME_ASSERT(end >= start);
3106 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003107 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003108 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003109 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003110}
3111
3112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003113RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003114 ASSERT_EQ(3, args.length());
3115
3116 CONVERT_ARG_CHECKED(String, subject, 0);
3117 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3118 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3119 HandleScope handles;
3120
3121 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3122
3123 if (match.is_null()) {
3124 return Failure::Exception();
3125 }
3126 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003127 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003128 }
3129 int length = subject->length();
3130
danno@chromium.org40cb8782011-05-25 07:58:50 +00003131 CompilationZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003132 ZoneList<int> offsets(8);
3133 do {
3134 int start;
3135 int end;
3136 {
3137 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003138 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003139 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3140 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3141 }
3142 offsets.Add(start);
3143 offsets.Add(end);
3144 int index = start < end ? end : end + 1;
3145 if (index > length) break;
3146 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3147 if (match.is_null()) {
3148 return Failure::Exception();
3149 }
3150 } while (!match->IsNull());
3151 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003152 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003153 for (int i = 0; i < matches ; i++) {
3154 int from = offsets.at(i * 2);
3155 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003156 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003157 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003158 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003159 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003160 result->set_length(Smi::FromInt(matches));
3161 return *result;
3162}
3163
3164
lrn@chromium.org25156de2010-04-06 13:10:27 +00003165// Two smis before and after the match, for very long strings.
3166const int kMaxBuilderEntriesPerRegExpMatch = 5;
3167
3168
3169static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3170 Handle<JSArray> last_match_info,
3171 int match_start,
3172 int match_end) {
3173 // Fill last_match_info with a single capture.
3174 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3175 AssertNoAllocation no_gc;
3176 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3177 RegExpImpl::SetLastCaptureCount(elements, 2);
3178 RegExpImpl::SetLastInput(elements, *subject);
3179 RegExpImpl::SetLastSubject(elements, *subject);
3180 RegExpImpl::SetCapture(elements, 0, match_start);
3181 RegExpImpl::SetCapture(elements, 1, match_end);
3182}
3183
3184
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003185template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003186static bool SearchStringMultiple(Isolate* isolate,
3187 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003188 Vector<const PatternChar> pattern,
3189 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003190 FixedArrayBuilder* builder,
3191 int* match_pos) {
3192 int pos = *match_pos;
3193 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003194 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003195 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003196 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003197 while (pos <= max_search_start) {
3198 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3199 *match_pos = pos;
3200 return false;
3201 }
3202 // Position of end of previous match.
3203 int match_end = pos + pattern_length;
3204 int new_pos = search.Search(subject, match_end);
3205 if (new_pos >= 0) {
3206 // A match.
3207 if (new_pos > match_end) {
3208 ReplacementStringBuilder::AddSubjectSlice(builder,
3209 match_end,
3210 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003211 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003212 pos = new_pos;
3213 builder->Add(pattern_string);
3214 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003215 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003216 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003217 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003218
lrn@chromium.org25156de2010-04-06 13:10:27 +00003219 if (pos < max_search_start) {
3220 ReplacementStringBuilder::AddSubjectSlice(builder,
3221 pos + pattern_length,
3222 subject_length);
3223 }
3224 *match_pos = pos;
3225 return true;
3226}
3227
3228
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003229static bool SearchStringMultiple(Isolate* isolate,
3230 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003231 Handle<String> pattern,
3232 Handle<JSArray> last_match_info,
3233 FixedArrayBuilder* builder) {
3234 ASSERT(subject->IsFlat());
3235 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003236
3237 // Treating as if a previous match was before first character.
3238 int match_pos = -pattern->length();
3239
3240 for (;;) { // Break when search complete.
3241 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3242 AssertNoAllocation no_gc;
3243 if (subject->IsAsciiRepresentation()) {
3244 Vector<const char> subject_vector = subject->ToAsciiVector();
3245 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003246 if (SearchStringMultiple(isolate,
3247 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003248 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003249 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003250 builder,
3251 &match_pos)) break;
3252 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003253 if (SearchStringMultiple(isolate,
3254 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003255 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003256 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003257 builder,
3258 &match_pos)) break;
3259 }
3260 } else {
3261 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3262 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003263 if (SearchStringMultiple(isolate,
3264 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003265 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003266 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003267 builder,
3268 &match_pos)) break;
3269 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003270 if (SearchStringMultiple(isolate,
3271 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003272 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003273 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003274 builder,
3275 &match_pos)) break;
3276 }
3277 }
3278 }
3279
3280 if (match_pos >= 0) {
3281 SetLastMatchInfoNoCaptures(subject,
3282 last_match_info,
3283 match_pos,
3284 match_pos + pattern->length());
3285 return true;
3286 }
3287 return false; // No matches at all.
3288}
3289
3290
3291static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003292 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003293 Handle<String> subject,
3294 Handle<JSRegExp> regexp,
3295 Handle<JSArray> last_match_array,
3296 FixedArrayBuilder* builder) {
3297 ASSERT(subject->IsFlat());
3298 int match_start = -1;
3299 int match_end = 0;
3300 int pos = 0;
3301 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3302 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3303
3304 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003305 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003306 int subject_length = subject->length();
3307
3308 for (;;) { // Break on failure, return on exception.
3309 RegExpImpl::IrregexpResult result =
3310 RegExpImpl::IrregexpExecOnce(regexp,
3311 subject,
3312 pos,
3313 register_vector);
3314 if (result == RegExpImpl::RE_SUCCESS) {
3315 match_start = register_vector[0];
3316 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3317 if (match_end < match_start) {
3318 ReplacementStringBuilder::AddSubjectSlice(builder,
3319 match_end,
3320 match_start);
3321 }
3322 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003323 HandleScope loop_scope(isolate);
3324 builder->Add(*isolate->factory()->NewSubString(subject,
3325 match_start,
3326 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003327 if (match_start != match_end) {
3328 pos = match_end;
3329 } else {
3330 pos = match_end + 1;
3331 if (pos > subject_length) break;
3332 }
3333 } else if (result == RegExpImpl::RE_FAILURE) {
3334 break;
3335 } else {
3336 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3337 return result;
3338 }
3339 }
3340
3341 if (match_start >= 0) {
3342 if (match_end < subject_length) {
3343 ReplacementStringBuilder::AddSubjectSlice(builder,
3344 match_end,
3345 subject_length);
3346 }
3347 SetLastMatchInfoNoCaptures(subject,
3348 last_match_array,
3349 match_start,
3350 match_end);
3351 return RegExpImpl::RE_SUCCESS;
3352 } else {
3353 return RegExpImpl::RE_FAILURE; // No matches at all.
3354 }
3355}
3356
3357
3358static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003359 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003360 Handle<String> subject,
3361 Handle<JSRegExp> regexp,
3362 Handle<JSArray> last_match_array,
3363 FixedArrayBuilder* builder) {
3364
3365 ASSERT(subject->IsFlat());
3366 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3367 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3368
3369 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003370 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003371
3372 RegExpImpl::IrregexpResult result =
3373 RegExpImpl::IrregexpExecOnce(regexp,
3374 subject,
3375 0,
3376 register_vector);
3377
3378 int capture_count = regexp->CaptureCount();
3379 int subject_length = subject->length();
3380
3381 // Position to search from.
3382 int pos = 0;
3383 // End of previous match. Differs from pos if match was empty.
3384 int match_end = 0;
3385 if (result == RegExpImpl::RE_SUCCESS) {
3386 // Need to keep a copy of the previous match for creating last_match_info
3387 // at the end, so we have two vectors that we swap between.
3388 OffsetsVector registers2(required_registers);
3389 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3390
3391 do {
3392 int match_start = register_vector[0];
3393 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3394 if (match_end < match_start) {
3395 ReplacementStringBuilder::AddSubjectSlice(builder,
3396 match_end,
3397 match_start);
3398 }
3399 match_end = register_vector[1];
3400
3401 {
3402 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003403 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003404 // Arguments array to replace function is match, captures, index and
3405 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003406 Handle<FixedArray> elements =
3407 isolate->factory()->NewFixedArray(3 + capture_count);
3408 Handle<String> match = isolate->factory()->NewSubString(subject,
3409 match_start,
3410 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003411 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003412 for (int i = 1; i <= capture_count; i++) {
3413 int start = register_vector[i * 2];
3414 if (start >= 0) {
3415 int end = register_vector[i * 2 + 1];
3416 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003417 Handle<String> substring = isolate->factory()->NewSubString(subject,
3418 start,
3419 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003420 elements->set(i, *substring);
3421 } else {
3422 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003423 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003424 }
3425 }
3426 elements->set(capture_count + 1, Smi::FromInt(match_start));
3427 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003428 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003429 }
3430 // Swap register vectors, so the last successful match is in
3431 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003432 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003433 prev_register_vector = register_vector;
3434 register_vector = tmp;
3435
3436 if (match_end > match_start) {
3437 pos = match_end;
3438 } else {
3439 pos = match_end + 1;
3440 if (pos > subject_length) {
3441 break;
3442 }
3443 }
3444
3445 result = RegExpImpl::IrregexpExecOnce(regexp,
3446 subject,
3447 pos,
3448 register_vector);
3449 } while (result == RegExpImpl::RE_SUCCESS);
3450
3451 if (result != RegExpImpl::RE_EXCEPTION) {
3452 // Finished matching, with at least one match.
3453 if (match_end < subject_length) {
3454 ReplacementStringBuilder::AddSubjectSlice(builder,
3455 match_end,
3456 subject_length);
3457 }
3458
3459 int last_match_capture_count = (capture_count + 1) * 2;
3460 int last_match_array_size =
3461 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3462 last_match_array->EnsureSize(last_match_array_size);
3463 AssertNoAllocation no_gc;
3464 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3465 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3466 RegExpImpl::SetLastSubject(elements, *subject);
3467 RegExpImpl::SetLastInput(elements, *subject);
3468 for (int i = 0; i < last_match_capture_count; i++) {
3469 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3470 }
3471 return RegExpImpl::RE_SUCCESS;
3472 }
3473 }
3474 // No matches at all, return failure or exception result directly.
3475 return result;
3476}
3477
3478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003479RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003480 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003481 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003482
3483 CONVERT_ARG_CHECKED(String, subject, 1);
3484 if (!subject->IsFlat()) { FlattenString(subject); }
3485 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3486 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3487 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3488
3489 ASSERT(last_match_info->HasFastElements());
3490 ASSERT(regexp->GetFlags().is_global());
3491 Handle<FixedArray> result_elements;
3492 if (result_array->HasFastElements()) {
3493 result_elements =
3494 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3495 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003496 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003497 }
3498 FixedArrayBuilder builder(result_elements);
3499
3500 if (regexp->TypeTag() == JSRegExp::ATOM) {
3501 Handle<String> pattern(
3502 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003503 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003504 if (SearchStringMultiple(isolate, subject, pattern,
3505 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003506 return *builder.ToJSArray(result_array);
3507 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003508 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003509 }
3510
3511 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3512
3513 RegExpImpl::IrregexpResult result;
3514 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003515 result = SearchRegExpNoCaptureMultiple(isolate,
3516 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003517 regexp,
3518 last_match_info,
3519 &builder);
3520 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003521 result = SearchRegExpMultiple(isolate,
3522 subject,
3523 regexp,
3524 last_match_info,
3525 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003526 }
3527 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003528 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003529 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3530 return Failure::Exception();
3531}
3532
3533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003534RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003535 NoHandleAllocation ha;
3536 ASSERT(args.length() == 2);
3537
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003538 // Fast case where the result is a one character string.
3539 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3540 int value = Smi::cast(args[0])->value();
3541 int radix = Smi::cast(args[1])->value();
3542 if (value >= 0 && value < radix) {
3543 RUNTIME_ASSERT(radix <= 36);
3544 // Character array used for conversion.
3545 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003546 return isolate->heap()->
3547 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003548 }
3549 }
3550
3551 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003552 CONVERT_DOUBLE_CHECKED(value, args[0]);
3553 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003554 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003555 }
3556 if (isinf(value)) {
3557 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003558 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003559 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003560 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003561 }
3562 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3563 int radix = FastD2I(radix_number);
3564 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3565 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003566 MaybeObject* result =
3567 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003568 DeleteArray(str);
3569 return result;
3570}
3571
3572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003573RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003574 NoHandleAllocation ha;
3575 ASSERT(args.length() == 2);
3576
3577 CONVERT_DOUBLE_CHECKED(value, args[0]);
3578 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003579 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003580 }
3581 if (isinf(value)) {
3582 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003583 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003584 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003585 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003586 }
3587 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3588 int f = FastD2I(f_number);
3589 RUNTIME_ASSERT(f >= 0);
3590 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003591 MaybeObject* res =
3592 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003593 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003594 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595}
3596
3597
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003598RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003599 NoHandleAllocation ha;
3600 ASSERT(args.length() == 2);
3601
3602 CONVERT_DOUBLE_CHECKED(value, args[0]);
3603 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003604 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003605 }
3606 if (isinf(value)) {
3607 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003608 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003609 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003610 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003611 }
3612 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3613 int f = FastD2I(f_number);
3614 RUNTIME_ASSERT(f >= -1 && f <= 20);
3615 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 MaybeObject* res =
3617 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003618 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620}
3621
3622
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003623RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003624 NoHandleAllocation ha;
3625 ASSERT(args.length() == 2);
3626
3627 CONVERT_DOUBLE_CHECKED(value, args[0]);
3628 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003629 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003630 }
3631 if (isinf(value)) {
3632 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003633 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003634 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003635 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003636 }
3637 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3638 int f = FastD2I(f_number);
3639 RUNTIME_ASSERT(f >= 1 && f <= 21);
3640 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003641 MaybeObject* res =
3642 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003644 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003645}
3646
3647
3648// Returns a single character string where first character equals
3649// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003650static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003651 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003652 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003653 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003654 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003655 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003656 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003657}
3658
3659
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003660MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3661 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003662 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003663 // Handle [] indexing on Strings
3664 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003665 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3666 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003667 }
3668
3669 // Handle [] indexing on String objects
3670 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003671 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3672 Handle<Object> result =
3673 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3674 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003675 }
3676
3677 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003678 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003679 return prototype->GetElement(index);
3680 }
3681
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003682 return GetElement(object, index);
3683}
3684
3685
lrn@chromium.org303ada72010-10-27 09:33:13 +00003686MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003687 return object->GetElement(index);
3688}
3689
3690
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003691MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3692 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003693 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003694 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003695
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003696 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003697 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003699 isolate->factory()->NewTypeError("non_object_property_load",
3700 HandleVector(args, 2));
3701 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003702 }
3703
3704 // Check if the given key is an array index.
3705 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003706 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003707 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003708 }
3709
3710 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003711 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003713 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003714 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 bool has_pending_exception = false;
3716 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003717 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003718 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003719 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003720 }
3721
ager@chromium.org32912102009-01-16 10:38:43 +00003722 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003723 // the element if so.
3724 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003725 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003726 } else {
3727 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003728 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003729 }
3730}
3731
3732
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003733RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003734 NoHandleAllocation ha;
3735 ASSERT(args.length() == 2);
3736
3737 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003738 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003739
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003740 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003741}
3742
3743
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003744// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003745RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003746 NoHandleAllocation ha;
3747 ASSERT(args.length() == 2);
3748
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003749 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003750 // itself.
3751 //
3752 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003753 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003754 // global proxy object never has properties. This is the case
3755 // because the global proxy object forwards everything to its hidden
3756 // prototype including local lookups.
3757 //
3758 // Additionally, we need to make sure that we do not cache results
3759 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003760 if (args[0]->IsJSObject() &&
3761 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003762 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003763 args[1]->IsString()) {
3764 JSObject* receiver = JSObject::cast(args[0]);
3765 String* key = String::cast(args[1]);
3766 if (receiver->HasFastProperties()) {
3767 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003768 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003769 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3770 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003771 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003772 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003773 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003774 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003775 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003776 LookupResult result;
3777 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003778 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003779 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003780 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003781 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003782 }
3783 } else {
3784 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003785 StringDictionary* dictionary = receiver->property_dictionary();
3786 int entry = dictionary->FindEntry(key);
3787 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003788 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003789 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003790 if (!receiver->IsGlobalObject()) return value;
3791 value = JSGlobalPropertyCell::cast(value)->value();
3792 if (!value->IsTheHole()) return value;
3793 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003794 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003795 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003796 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3797 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003798 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003799 Handle<String> str = args.at<String>(0);
3800 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003801 if (index >= 0 && index < str->length()) {
3802 Handle<Object> result = GetCharAt(str, index);
3803 return *result;
3804 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003805 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003806
3807 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003808 return Runtime::GetObjectProperty(isolate,
3809 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003810 args.at<Object>(1));
3811}
3812
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003813// Implements part of 8.12.9 DefineOwnProperty.
3814// There are 3 cases that lead here:
3815// Step 4b - define a new accessor property.
3816// Steps 9c & 12 - replace an existing data property with an accessor property.
3817// Step 12 - update an existing accessor property with an accessor or generic
3818// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003819RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003820 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003821 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003822 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3823 CONVERT_CHECKED(String, name, args[1]);
3824 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003825 Object* fun = args[3];
3826 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003827 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3828 int unchecked = flag_attr->value();
3829 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3830 RUNTIME_ASSERT(!obj->IsNull());
3831 LookupResult result;
3832 obj->LocalLookupRealNamedProperty(name, &result);
3833
3834 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3835 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3836 // delete it to avoid running into trouble in DefineAccessor, which
3837 // handles this incorrectly if the property is readonly (does nothing)
3838 if (result.IsProperty() &&
3839 (result.type() == FIELD || result.type() == NORMAL
3840 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003841 Object* ok;
3842 { MaybeObject* maybe_ok =
3843 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3844 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3845 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003846 }
3847 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3848}
3849
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003850// Implements part of 8.12.9 DefineOwnProperty.
3851// There are 3 cases that lead here:
3852// Step 4a - define a new data property.
3853// Steps 9b & 12 - replace an existing accessor property with a data property.
3854// Step 12 - update an existing data property with a data or generic
3855// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003856RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003857 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003858 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003859 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3860 CONVERT_ARG_CHECKED(String, name, 1);
3861 Handle<Object> obj_value = args.at<Object>(2);
3862
3863 CONVERT_CHECKED(Smi, flag, args[3]);
3864 int unchecked = flag->value();
3865 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3866
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003867 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3868
3869 // Check if this is an element.
3870 uint32_t index;
3871 bool is_element = name->AsArrayIndex(&index);
3872
3873 // Special case for elements if any of the flags are true.
3874 // If elements are in fast case we always implicitly assume that:
3875 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3876 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3877 is_element) {
3878 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003879 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003880 // We do not need to do access checks here since these has already
3881 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003882 Handle<Object> proto(js_object->GetPrototype());
3883 // If proxy is detached, ignore the assignment. Alternatively,
3884 // we could throw an exception.
3885 if (proto->IsNull()) return *obj_value;
3886 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003887 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003888 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003889 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003890 // Make sure that we never go back to fast case.
3891 dictionary->set_requires_slow_elements();
3892 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003893 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003894 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003895 }
3896
ager@chromium.org5c838252010-02-19 08:53:10 +00003897 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003898 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003899
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003900 // To be compatible with safari we do not change the value on API objects
3901 // in defineProperty. Firefox disagrees here, and actually changes the value.
3902 if (result.IsProperty() &&
3903 (result.type() == CALLBACKS) &&
3904 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003905 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003906 }
3907
ager@chromium.org5c838252010-02-19 08:53:10 +00003908 // Take special care when attributes are different and there is already
3909 // a property. For simplicity we normalize the property which enables us
3910 // to not worry about changing the instance_descriptor and creating a new
3911 // map. The current version of SetObjectProperty does not handle attributes
3912 // correctly in the case where a property is a field and is reset with
3913 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003914 if (result.IsProperty() &&
3915 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003916 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003917 if (js_object->IsJSGlobalProxy()) {
3918 // Since the result is a property, the prototype will exist so
3919 // we don't have to check for null.
3920 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003921 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003922 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003923 // Use IgnoreAttributes version since a readonly property may be
3924 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003925 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3926 *obj_value,
3927 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003928 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003929
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003930 return Runtime::ForceSetObjectProperty(isolate,
3931 js_object,
3932 name,
3933 obj_value,
3934 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003935}
3936
3937
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003938MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3939 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003940 Handle<Object> key,
3941 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003942 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003943 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003944 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003945
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003946 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003947 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003949 isolate->factory()->NewTypeError("non_object_property_store",
3950 HandleVector(args, 2));
3951 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003952 }
3953
3954 // If the object isn't a JavaScript object, we ignore the store.
3955 if (!object->IsJSObject()) return *value;
3956
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003957 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3958
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003959 // Check if the given key is an array index.
3960 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003961 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003962 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3963 // of a string using [] notation. We need to support this too in
3964 // JavaScript.
3965 // In the case of a String object we just need to redirect the assignment to
3966 // the underlying string if the index is in range. Since the underlying
3967 // string does nothing with the assignment then we can ignore such
3968 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003969 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003970 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003971 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003972
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003973 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003974 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003975 return *value;
3976 }
3977
3978 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003979 Handle<Object> result;
3980 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003981 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003982 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003983 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003984 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003985 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003987 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003988 return *value;
3989 }
3990
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003991 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003992 bool has_pending_exception = false;
3993 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3994 if (has_pending_exception) return Failure::Exception();
3995 Handle<String> name = Handle<String>::cast(converted);
3996
3997 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003998 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003999 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004000 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004001 }
4002}
4003
4004
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004005MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4006 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004007 Handle<Object> key,
4008 Handle<Object> value,
4009 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004010 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004011
4012 // Check if the given key is an array index.
4013 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004014 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004015 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4016 // of a string using [] notation. We need to support this too in
4017 // JavaScript.
4018 // In the case of a String object we just need to redirect the assignment to
4019 // the underlying string if the index is in range. Since the underlying
4020 // string does nothing with the assignment then we can ignore such
4021 // assignments.
4022 if (js_object->IsStringObjectWithCharacterAt(index)) {
4023 return *value;
4024 }
4025
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004026 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004027 }
4028
4029 if (key->IsString()) {
4030 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004031 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004032 } else {
4033 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004034 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004035 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4036 *value,
4037 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004038 }
4039 }
4040
4041 // Call-back into JavaScript to convert the key to a string.
4042 bool has_pending_exception = false;
4043 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4044 if (has_pending_exception) return Failure::Exception();
4045 Handle<String> name = Handle<String>::cast(converted);
4046
4047 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004048 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004049 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004050 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004051 }
4052}
4053
4054
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004055MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4056 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004057 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004058 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004059
4060 // Check if the given key is an array index.
4061 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004062 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004063 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4064 // characters of a string using [] notation. In the case of a
4065 // String object we just need to redirect the deletion to the
4066 // underlying string if the index is in range. Since the
4067 // underlying string does nothing with the deletion, we can ignore
4068 // such deletions.
4069 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004070 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004071 }
4072
4073 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4074 }
4075
4076 Handle<String> key_string;
4077 if (key->IsString()) {
4078 key_string = Handle<String>::cast(key);
4079 } else {
4080 // Call-back into JavaScript to convert the key to a string.
4081 bool has_pending_exception = false;
4082 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4083 if (has_pending_exception) return Failure::Exception();
4084 key_string = Handle<String>::cast(converted);
4085 }
4086
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004087 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004088 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4089}
4090
4091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004092RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004094 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004095
4096 Handle<Object> object = args.at<Object>(0);
4097 Handle<Object> key = args.at<Object>(1);
4098 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004099 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4100 RUNTIME_ASSERT(
4101 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004103 PropertyAttributes attributes =
4104 static_cast<PropertyAttributes>(unchecked_attributes);
4105
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004106 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004107 if (args.length() == 5) {
4108 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4109 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4110 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004111 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004113
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004114 return Runtime::SetObjectProperty(isolate,
4115 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004116 key,
4117 value,
4118 attributes,
4119 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004120}
4121
4122
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004123// Set the ES5 native flag on the function.
4124// This is used to decide if we should transform null and undefined
4125// into the global object when doing call and apply.
4126RUNTIME_FUNCTION(MaybeObject*, Runtime_SetES5Flag) {
4127 NoHandleAllocation ha;
4128 RUNTIME_ASSERT(args.length() == 1);
4129
4130 Handle<Object> object = args.at<Object>(0);
4131
4132 if (object->IsJSFunction()) {
4133 JSFunction* func = JSFunction::cast(*object);
4134 func->shared()->set_es5_native(true);
4135 }
4136 return isolate->heap()->undefined_value();
4137}
4138
4139
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004140// Set a local property, even if it is READ_ONLY. If the property does not
4141// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004142RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004144 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004145 CONVERT_CHECKED(JSObject, object, args[0]);
4146 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004147 // Compute attributes.
4148 PropertyAttributes attributes = NONE;
4149 if (args.length() == 4) {
4150 CONVERT_CHECKED(Smi, value_obj, args[3]);
4151 int unchecked_value = value_obj->value();
4152 // Only attribute bits should be set.
4153 RUNTIME_ASSERT(
4154 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4155 attributes = static_cast<PropertyAttributes>(unchecked_value);
4156 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004157
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004158 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004159 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004160}
4161
4162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004163RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004165 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004166
4167 CONVERT_CHECKED(JSObject, object, args[0]);
4168 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004169 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004170 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004171 ? JSObject::STRICT_DELETION
4172 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173}
4174
4175
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004176static Object* HasLocalPropertyImplementation(Isolate* isolate,
4177 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004178 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004179 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004180 // Handle hidden prototypes. If there's a hidden prototype above this thing
4181 // then we have to check it for properties, because they are supposed to
4182 // look like they are on this object.
4183 Handle<Object> proto(object->GetPrototype());
4184 if (proto->IsJSObject() &&
4185 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004186 return HasLocalPropertyImplementation(isolate,
4187 Handle<JSObject>::cast(proto),
4188 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004189 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004190 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004191}
4192
4193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004194RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004195 NoHandleAllocation ha;
4196 ASSERT(args.length() == 2);
4197 CONVERT_CHECKED(String, key, args[1]);
4198
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004199 uint32_t index;
4200 const bool key_is_array_index = key->AsArrayIndex(&index);
4201
ager@chromium.org9085a012009-05-11 19:22:57 +00004202 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004204 if (obj->IsJSObject()) {
4205 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004206 // Fast case: either the key is a real named property or it is not
4207 // an array index and there are no interceptors or hidden
4208 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004209 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004210 Map* map = object->map();
4211 if (!key_is_array_index &&
4212 !map->has_named_interceptor() &&
4213 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4214 return isolate->heap()->false_value();
4215 }
4216 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004217 HandleScope scope(isolate);
4218 return HasLocalPropertyImplementation(isolate,
4219 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004220 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004221 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004222 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004223 String* string = String::cast(obj);
4224 if (index < static_cast<uint32_t>(string->length())) {
4225 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004226 }
4227 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004228 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004229}
4230
4231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004232RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004233 NoHandleAllocation na;
4234 ASSERT(args.length() == 2);
4235
4236 // Only JS objects can have properties.
4237 if (args[0]->IsJSObject()) {
4238 JSObject* object = JSObject::cast(args[0]);
4239 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004240 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004241 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004242 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004243}
4244
4245
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004246RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004247 NoHandleAllocation na;
4248 ASSERT(args.length() == 2);
4249
4250 // Only JS objects can have elements.
4251 if (args[0]->IsJSObject()) {
4252 JSObject* object = JSObject::cast(args[0]);
4253 CONVERT_CHECKED(Smi, index_obj, args[1]);
4254 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004255 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004256 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004257 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004258}
4259
4260
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004261RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004262 NoHandleAllocation ha;
4263 ASSERT(args.length() == 2);
4264
4265 CONVERT_CHECKED(JSObject, object, args[0]);
4266 CONVERT_CHECKED(String, key, args[1]);
4267
4268 uint32_t index;
4269 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004270 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004271 }
4272
ager@chromium.org870a0b62008-11-04 11:43:05 +00004273 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004274 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004275}
4276
4277
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004278RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004279 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004280 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004281 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004282 return *GetKeysFor(object);
4283}
4284
4285
4286// Returns either a FixedArray as Runtime_GetPropertyNames,
4287// or, if the given object has an enum cache that contains
4288// all enumerable properties of the object and its prototypes
4289// have none, the map of the object. This is used to speed up
4290// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004291RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004292 ASSERT(args.length() == 1);
4293
4294 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4295
4296 if (raw_object->IsSimpleEnum()) return raw_object->map();
4297
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004298 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004299 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004300 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4301 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004302
4303 // Test again, since cache may have been built by preceding call.
4304 if (object->IsSimpleEnum()) return object->map();
4305
4306 return *content;
4307}
4308
4309
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004310// Find the length of the prototype chain that is to to handled as one. If a
4311// prototype object is hidden it is to be viewed as part of the the object it
4312// is prototype for.
4313static int LocalPrototypeChainLength(JSObject* obj) {
4314 int count = 1;
4315 Object* proto = obj->GetPrototype();
4316 while (proto->IsJSObject() &&
4317 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4318 count++;
4319 proto = JSObject::cast(proto)->GetPrototype();
4320 }
4321 return count;
4322}
4323
4324
4325// Return the names of the local named properties.
4326// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004327RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004328 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004329 ASSERT(args.length() == 1);
4330 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004331 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004332 }
4333 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4334
4335 // Skip the global proxy as it has no properties and always delegates to the
4336 // real global object.
4337 if (obj->IsJSGlobalProxy()) {
4338 // Only collect names if access is permitted.
4339 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004340 !isolate->MayNamedAccess(*obj,
4341 isolate->heap()->undefined_value(),
4342 v8::ACCESS_KEYS)) {
4343 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4344 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004345 }
4346 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4347 }
4348
4349 // Find the number of objects making up this.
4350 int length = LocalPrototypeChainLength(*obj);
4351
4352 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004353 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004354 int total_property_count = 0;
4355 Handle<JSObject> jsproto = obj;
4356 for (int i = 0; i < length; i++) {
4357 // Only collect names if access is permitted.
4358 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004359 !isolate->MayNamedAccess(*jsproto,
4360 isolate->heap()->undefined_value(),
4361 v8::ACCESS_KEYS)) {
4362 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4363 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004364 }
4365 int n;
4366 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4367 local_property_count[i] = n;
4368 total_property_count += n;
4369 if (i < length - 1) {
4370 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4371 }
4372 }
4373
4374 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004375 Handle<FixedArray> names =
4376 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004377
4378 // Get the property names.
4379 jsproto = obj;
4380 int proto_with_hidden_properties = 0;
4381 for (int i = 0; i < length; i++) {
4382 jsproto->GetLocalPropertyNames(*names,
4383 i == 0 ? 0 : local_property_count[i - 1]);
4384 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4385 proto_with_hidden_properties++;
4386 }
4387 if (i < length - 1) {
4388 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4389 }
4390 }
4391
4392 // Filter out name of hidden propeties object.
4393 if (proto_with_hidden_properties > 0) {
4394 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004395 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004396 names->length() - proto_with_hidden_properties);
4397 int dest_pos = 0;
4398 for (int i = 0; i < total_property_count; i++) {
4399 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004400 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004401 continue;
4402 }
4403 names->set(dest_pos++, name);
4404 }
4405 }
4406
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004407 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004408}
4409
4410
4411// Return the names of the local indexed properties.
4412// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004413RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004414 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004415 ASSERT(args.length() == 1);
4416 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004417 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004418 }
4419 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4420
4421 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004422 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004423 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004424 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004425}
4426
4427
4428// Return information on whether an object has a named or indexed interceptor.
4429// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004430RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004431 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004432 ASSERT(args.length() == 1);
4433 if (!args[0]->IsJSObject()) {
4434 return Smi::FromInt(0);
4435 }
4436 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4437
4438 int result = 0;
4439 if (obj->HasNamedInterceptor()) result |= 2;
4440 if (obj->HasIndexedInterceptor()) result |= 1;
4441
4442 return Smi::FromInt(result);
4443}
4444
4445
4446// Return property names from named interceptor.
4447// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004448RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004449 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004450 ASSERT(args.length() == 1);
4451 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4452
4453 if (obj->HasNamedInterceptor()) {
4454 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4455 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4456 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004457 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004458}
4459
4460
4461// Return element names from indexed interceptor.
4462// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004463RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004464 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004465 ASSERT(args.length() == 1);
4466 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4467
4468 if (obj->HasIndexedInterceptor()) {
4469 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4470 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4471 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004472 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004473}
4474
4475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004476RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004477 ASSERT_EQ(args.length(), 1);
4478 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004479 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004480 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004481
4482 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004483 // Do access checks before going to the global object.
4484 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004485 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004486 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004487 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4488 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004489 }
4490
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004491 Handle<Object> proto(object->GetPrototype());
4492 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004493 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004494 object = Handle<JSObject>::cast(proto);
4495 }
4496
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004497 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4498 LOCAL_ONLY);
4499 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4500 // property array and since the result is mutable we have to create
4501 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004502 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004503 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004504 for (int i = 0; i < length; i++) {
4505 Object* entry = contents->get(i);
4506 if (entry->IsString()) {
4507 copy->set(i, entry);
4508 } else {
4509 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004510 HandleScope scope(isolate);
4511 Handle<Object> entry_handle(entry, isolate);
4512 Handle<Object> entry_str =
4513 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004514 copy->set(i, *entry_str);
4515 }
4516 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004517 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004518}
4519
4520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004521RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004522 NoHandleAllocation ha;
4523 ASSERT(args.length() == 1);
4524
4525 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004526 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004527 it.AdvanceToArgumentsFrame();
4528 JavaScriptFrame* frame = it.frame();
4529
4530 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004531 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004532
4533 // Try to convert the key to an index. If successful and within
4534 // index return the the argument from the frame.
4535 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004536 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004537 return frame->GetParameter(index);
4538 }
4539
4540 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004541 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004542 bool exception = false;
4543 Handle<Object> converted =
4544 Execution::ToString(args.at<Object>(0), &exception);
4545 if (exception) return Failure::Exception();
4546 Handle<String> key = Handle<String>::cast(converted);
4547
4548 // Try to convert the string key into an array index.
4549 if (key->AsArrayIndex(&index)) {
4550 if (index < n) {
4551 return frame->GetParameter(index);
4552 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004553 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004554 }
4555 }
4556
4557 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004558 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4559 if (key->Equals(isolate->heap()->callee_symbol())) {
4560 Object* function = frame->function();
4561 if (function->IsJSFunction() &&
4562 JSFunction::cast(function)->shared()->strict_mode()) {
4563 return isolate->Throw(*isolate->factory()->NewTypeError(
4564 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4565 }
4566 return function;
4567 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004568
4569 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004570 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004571}
4572
4573
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004574RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004575 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004576
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004577 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004578 Handle<Object> object = args.at<Object>(0);
4579 if (object->IsJSObject()) {
4580 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004581 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004582 MaybeObject* ok = js_object->TransformToFastProperties(0);
4583 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004584 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004585 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004586 return *object;
4587}
4588
4589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004590RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004591 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004592
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004593 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004594 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004595 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004596 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004597 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004598 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004599 return *object;
4600}
4601
4602
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004603RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004604 NoHandleAllocation ha;
4605 ASSERT(args.length() == 1);
4606
4607 return args[0]->ToBoolean();
4608}
4609
4610
4611// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4612// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004613RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004614 NoHandleAllocation ha;
4615
4616 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004617 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004618 HeapObject* heap_obj = HeapObject::cast(obj);
4619
4620 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004621 if (heap_obj->map()->is_undetectable()) {
4622 return isolate->heap()->undefined_symbol();
4623 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004624
4625 InstanceType instance_type = heap_obj->map()->instance_type();
4626 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004627 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004628 }
4629
4630 switch (instance_type) {
4631 case ODDBALL_TYPE:
4632 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004633 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004634 }
4635 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004636 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004637 }
4638 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004639 return isolate->heap()->undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004640 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004641 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004642 default:
4643 // For any kind of object not handled above, the spec rule for
4644 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004645 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004646 }
4647}
4648
4649
lrn@chromium.org25156de2010-04-06 13:10:27 +00004650static bool AreDigits(const char*s, int from, int to) {
4651 for (int i = from; i < to; i++) {
4652 if (s[i] < '0' || s[i] > '9') return false;
4653 }
4654
4655 return true;
4656}
4657
4658
4659static int ParseDecimalInteger(const char*s, int from, int to) {
4660 ASSERT(to - from < 10); // Overflow is not possible.
4661 ASSERT(from < to);
4662 int d = s[from] - '0';
4663
4664 for (int i = from + 1; i < to; i++) {
4665 d = 10 * d + (s[i] - '0');
4666 }
4667
4668 return d;
4669}
4670
4671
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004672RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004673 NoHandleAllocation ha;
4674 ASSERT(args.length() == 1);
4675 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004676 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004677
4678 // Fast case: short integer or some sorts of junk values.
4679 int len = subject->length();
4680 if (subject->IsSeqAsciiString()) {
4681 if (len == 0) return Smi::FromInt(0);
4682
4683 char const* data = SeqAsciiString::cast(subject)->GetChars();
4684 bool minus = (data[0] == '-');
4685 int start_pos = (minus ? 1 : 0);
4686
4687 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004688 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004689 } else if (data[start_pos] > '9') {
4690 // Fast check for a junk value. A valid string may start from a
4691 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4692 // the 'I' character ('Infinity'). All of that have codes not greater than
4693 // '9' except 'I'.
4694 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004695 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004696 }
4697 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4698 // The maximal/minimal smi has 10 digits. If the string has less digits we
4699 // know it will fit into the smi-data type.
4700 int d = ParseDecimalInteger(data, start_pos, len);
4701 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004702 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004703 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004704 } else if (!subject->HasHashCode() &&
4705 len <= String::kMaxArrayIndexSize &&
4706 (len == 1 || data[0] != '0')) {
4707 // String hash is not calculated yet but all the data are present.
4708 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004709 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004710#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004711 subject->Hash(); // Force hash calculation.
4712 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4713 static_cast<int>(hash));
4714#endif
4715 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004716 }
4717 return Smi::FromInt(d);
4718 }
4719 }
4720
4721 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004722 return isolate->heap()->NumberFromDouble(
4723 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004724}
4725
4726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004727RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004728 NoHandleAllocation ha;
4729 ASSERT(args.length() == 1);
4730
4731 CONVERT_CHECKED(JSArray, codes, args[0]);
4732 int length = Smi::cast(codes->length())->value();
4733
4734 // Check if the string can be ASCII.
4735 int i;
4736 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004737 Object* element;
4738 { MaybeObject* maybe_element = codes->GetElement(i);
4739 // We probably can't get an exception here, but just in order to enforce
4740 // the checking of inputs in the runtime calls we check here.
4741 if (!maybe_element->ToObject(&element)) return maybe_element;
4742 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004743 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4744 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4745 break;
4746 }
4747
lrn@chromium.org303ada72010-10-27 09:33:13 +00004748 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004749 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004750 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004751 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004752 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004753 }
4754
lrn@chromium.org303ada72010-10-27 09:33:13 +00004755 Object* object = NULL;
4756 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004757 String* result = String::cast(object);
4758 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004759 Object* element;
4760 { MaybeObject* maybe_element = codes->GetElement(i);
4761 if (!maybe_element->ToObject(&element)) return maybe_element;
4762 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004764 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004765 }
4766 return result;
4767}
4768
4769
4770// kNotEscaped is generated by the following:
4771//
4772// #!/bin/perl
4773// for (my $i = 0; $i < 256; $i++) {
4774// print "\n" if $i % 16 == 0;
4775// my $c = chr($i);
4776// my $escaped = 1;
4777// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4778// print $escaped ? "0, " : "1, ";
4779// }
4780
4781
4782static bool IsNotEscaped(uint16_t character) {
4783 // Only for 8 bit characters, the rest are always escaped (in a different way)
4784 ASSERT(character < 256);
4785 static const char kNotEscaped[256] = {
4786 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4787 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4788 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4789 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4790 1, 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, 1,
4792 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4793 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4801 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4802 };
4803 return kNotEscaped[character] != 0;
4804}
4805
4806
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004807RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004808 const char hex_chars[] = "0123456789ABCDEF";
4809 NoHandleAllocation ha;
4810 ASSERT(args.length() == 1);
4811 CONVERT_CHECKED(String, source, args[0]);
4812
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004813 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814
4815 int escaped_length = 0;
4816 int length = source->length();
4817 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004818 Access<StringInputBuffer> buffer(
4819 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004820 buffer->Reset(source);
4821 while (buffer->has_more()) {
4822 uint16_t character = buffer->GetNext();
4823 if (character >= 256) {
4824 escaped_length += 6;
4825 } else if (IsNotEscaped(character)) {
4826 escaped_length++;
4827 } else {
4828 escaped_length += 3;
4829 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004830 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004831 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004832 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004833 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004834 return Failure::OutOfMemoryException();
4835 }
4836 }
4837 }
4838 // No length change implies no change. Return original string if no change.
4839 if (escaped_length == length) {
4840 return source;
4841 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004842 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004843 { MaybeObject* maybe_o =
4844 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004845 if (!maybe_o->ToObject(&o)) return maybe_o;
4846 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004847 String* destination = String::cast(o);
4848 int dest_position = 0;
4849
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004850 Access<StringInputBuffer> buffer(
4851 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004852 buffer->Rewind();
4853 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004854 uint16_t chr = buffer->GetNext();
4855 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004856 destination->Set(dest_position, '%');
4857 destination->Set(dest_position+1, 'u');
4858 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4859 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4860 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4861 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004862 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004863 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004864 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004865 dest_position++;
4866 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004867 destination->Set(dest_position, '%');
4868 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4869 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004870 dest_position += 3;
4871 }
4872 }
4873 return destination;
4874}
4875
4876
4877static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4878 static const signed char kHexValue['g'] = {
4879 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4880 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4881 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4882 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4883 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4884 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4885 -1, 10, 11, 12, 13, 14, 15 };
4886
4887 if (character1 > 'f') return -1;
4888 int hi = kHexValue[character1];
4889 if (hi == -1) return -1;
4890 if (character2 > 'f') return -1;
4891 int lo = kHexValue[character2];
4892 if (lo == -1) return -1;
4893 return (hi << 4) + lo;
4894}
4895
4896
ager@chromium.org870a0b62008-11-04 11:43:05 +00004897static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004898 int i,
4899 int length,
4900 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004901 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004902 int32_t hi = 0;
4903 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004904 if (character == '%' &&
4905 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004906 source->Get(i + 1) == 'u' &&
4907 (hi = TwoDigitHex(source->Get(i + 2),
4908 source->Get(i + 3))) != -1 &&
4909 (lo = TwoDigitHex(source->Get(i + 4),
4910 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004911 *step = 6;
4912 return (hi << 8) + lo;
4913 } else if (character == '%' &&
4914 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004915 (lo = TwoDigitHex(source->Get(i + 1),
4916 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004917 *step = 3;
4918 return lo;
4919 } else {
4920 *step = 1;
4921 return character;
4922 }
4923}
4924
4925
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004926RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004927 NoHandleAllocation ha;
4928 ASSERT(args.length() == 1);
4929 CONVERT_CHECKED(String, source, args[0]);
4930
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004931 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004932
4933 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004934 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004935
4936 int unescaped_length = 0;
4937 for (int i = 0; i < length; unescaped_length++) {
4938 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004939 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004940 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004941 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004942 i += step;
4943 }
4944
4945 // No length change implies no change. Return original string if no change.
4946 if (unescaped_length == length)
4947 return source;
4948
lrn@chromium.org303ada72010-10-27 09:33:13 +00004949 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004950 { MaybeObject* maybe_o =
4951 ascii ?
4952 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4953 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004954 if (!maybe_o->ToObject(&o)) return maybe_o;
4955 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004956 String* destination = String::cast(o);
4957
4958 int dest_position = 0;
4959 for (int i = 0; i < length; dest_position++) {
4960 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004961 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004962 i += step;
4963 }
4964 return destination;
4965}
4966
4967
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004968static const unsigned int kQuoteTableLength = 128u;
4969
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004970static const int kJsonQuotesCharactersPerEntry = 8;
4971static const char* const JsonQuotes =
4972 "\\u0000 \\u0001 \\u0002 \\u0003 "
4973 "\\u0004 \\u0005 \\u0006 \\u0007 "
4974 "\\b \\t \\n \\u000b "
4975 "\\f \\r \\u000e \\u000f "
4976 "\\u0010 \\u0011 \\u0012 \\u0013 "
4977 "\\u0014 \\u0015 \\u0016 \\u0017 "
4978 "\\u0018 \\u0019 \\u001a \\u001b "
4979 "\\u001c \\u001d \\u001e \\u001f "
4980 " ! \\\" # "
4981 "$ % & ' "
4982 "( ) * + "
4983 ", - . / "
4984 "0 1 2 3 "
4985 "4 5 6 7 "
4986 "8 9 : ; "
4987 "< = > ? "
4988 "@ A B C "
4989 "D E F G "
4990 "H I J K "
4991 "L M N O "
4992 "P Q R S "
4993 "T U V W "
4994 "X Y Z [ "
4995 "\\\\ ] ^ _ "
4996 "` a b c "
4997 "d e f g "
4998 "h i j k "
4999 "l m n o "
5000 "p q r s "
5001 "t u v w "
5002 "x y z { "
5003 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005004
5005
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005006// For a string that is less than 32k characters it should always be
5007// possible to allocate it in new space.
5008static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5009
5010
5011// Doing JSON quoting cannot make the string more than this many times larger.
5012static const int kJsonQuoteWorstCaseBlowup = 6;
5013
5014
5015// Covers the entire ASCII range (all other characters are unchanged by JSON
5016// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005017static const byte JsonQuoteLengths[kQuoteTableLength] = {
5018 6, 6, 6, 6, 6, 6, 6, 6,
5019 2, 2, 2, 6, 2, 2, 6, 6,
5020 6, 6, 6, 6, 6, 6, 6, 6,
5021 6, 6, 6, 6, 6, 6, 6, 6,
5022 1, 1, 2, 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, 1, 1, 1, 1,
5028 1, 1, 1, 1, 1, 1, 1, 1,
5029 1, 1, 1, 1, 2, 1, 1, 1,
5030 1, 1, 1, 1, 1, 1, 1, 1,
5031 1, 1, 1, 1, 1, 1, 1, 1,
5032 1, 1, 1, 1, 1, 1, 1, 1,
5033 1, 1, 1, 1, 1, 1, 1, 1,
5034};
5035
5036
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005037template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005038MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005039
5040
5041template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005042MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5043 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005044}
5045
5046
5047template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005048MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5049 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005050}
5051
5052
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005053template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005054static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5055 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005056 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005057 const Char* read_cursor = characters.start();
5058 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005059 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005060 int quoted_length = kSpaceForQuotes;
5061 while (read_cursor < end) {
5062 Char c = *(read_cursor++);
5063 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5064 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005065 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005066 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005067 }
5068 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005069 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5070 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005071 Object* new_object;
5072 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005073 return new_alloc;
5074 }
5075 StringType* new_string = StringType::cast(new_object);
5076
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005077 Char* write_cursor = reinterpret_cast<Char*>(
5078 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005079 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005080 *(write_cursor++) = '"';
5081
5082 read_cursor = characters.start();
5083 while (read_cursor < end) {
5084 Char c = *(read_cursor++);
5085 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5086 *(write_cursor++) = c;
5087 } else {
5088 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5089 const char* replacement = JsonQuotes +
5090 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5091 for (int i = 0; i < len; i++) {
5092 *write_cursor++ = *replacement++;
5093 }
5094 }
5095 }
5096 *(write_cursor++) = '"';
5097 return new_string;
5098}
5099
5100
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005101template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005102static MaybeObject* QuoteJsonString(Isolate* isolate,
5103 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005104 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005105 isolate->counters()->quote_json_char_count()->Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005106 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005107 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
5108 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005109 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005110 }
5111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005112 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5113 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005114 Object* new_object;
5115 if (!new_alloc->ToObject(&new_object)) {
5116 return new_alloc;
5117 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005118 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005119 // Even if our string is small enough to fit in new space we still have to
5120 // handle it being allocated in old space as may happen in the third
5121 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5122 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005123 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005124 }
5125 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005126 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005127
5128 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5129 Char* write_cursor = reinterpret_cast<Char*>(
5130 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005131 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005132 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005133
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005134 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005135 const Char* end = read_cursor + length;
5136 while (read_cursor < end) {
5137 Char c = *(read_cursor++);
5138 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5139 *(write_cursor++) = c;
5140 } else {
5141 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5142 const char* replacement = JsonQuotes +
5143 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5144 write_cursor[0] = replacement[0];
5145 if (len > 1) {
5146 write_cursor[1] = replacement[1];
5147 if (len > 2) {
5148 ASSERT(len == 6);
5149 write_cursor[2] = replacement[2];
5150 write_cursor[3] = replacement[3];
5151 write_cursor[4] = replacement[4];
5152 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005153 }
5154 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005155 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005156 }
5157 }
5158 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005159
5160 int final_length = static_cast<int>(
5161 write_cursor - reinterpret_cast<Char*>(
5162 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005163 isolate->heap()->new_space()->
5164 template ShrinkStringAtAllocationBoundary<StringType>(
5165 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005166 return new_string;
5167}
5168
5169
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005170RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005171 NoHandleAllocation ha;
5172 CONVERT_CHECKED(String, str, args[0]);
5173 if (!str->IsFlat()) {
5174 MaybeObject* try_flatten = str->TryFlatten();
5175 Object* flat;
5176 if (!try_flatten->ToObject(&flat)) {
5177 return try_flatten;
5178 }
5179 str = String::cast(flat);
5180 ASSERT(str->IsFlat());
5181 }
5182 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005183 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5184 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005185 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005186 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5187 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005188 }
5189}
5190
5191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005192RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005193 NoHandleAllocation ha;
5194 CONVERT_CHECKED(String, str, args[0]);
5195 if (!str->IsFlat()) {
5196 MaybeObject* try_flatten = str->TryFlatten();
5197 Object* flat;
5198 if (!try_flatten->ToObject(&flat)) {
5199 return try_flatten;
5200 }
5201 str = String::cast(flat);
5202 ASSERT(str->IsFlat());
5203 }
5204 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005205 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5206 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005207 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005208 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5209 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005210 }
5211}
5212
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005213RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005214 NoHandleAllocation ha;
5215
5216 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005217 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005218
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005219 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005220
lrn@chromium.org25156de2010-04-06 13:10:27 +00005221 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005222 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005223 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005224}
5225
5226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005227RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228 NoHandleAllocation ha;
5229 CONVERT_CHECKED(String, str, args[0]);
5230
5231 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005232 double value = StringToDouble(isolate->unicode_cache(),
5233 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005234
5235 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005236 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005237}
5238
5239
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005240template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005241MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005242 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005243 String* s,
5244 int length,
5245 int input_string_length,
5246 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005247 // We try this twice, once with the assumption that the result is no longer
5248 // than the input and, if that assumption breaks, again with the exact
5249 // length. This may not be pretty, but it is nicer than what was here before
5250 // and I hereby claim my vaffel-is.
5251 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005252 // Allocate the resulting string.
5253 //
5254 // NOTE: This assumes that the upper/lower case of an ascii
5255 // character is also ascii. This is currently the case, but it
5256 // might break in the future if we implement more context and locale
5257 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005258 Object* o;
5259 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005260 ? isolate->heap()->AllocateRawAsciiString(length)
5261 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005262 if (!maybe_o->ToObject(&o)) return maybe_o;
5263 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005264 String* result = String::cast(o);
5265 bool has_changed_character = false;
5266
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005267 // Convert all characters to upper case, assuming that they will fit
5268 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005269 Access<StringInputBuffer> buffer(
5270 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005271 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005272 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005273 // We can assume that the string is not empty
5274 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005275 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005276 bool has_next = buffer->has_more();
5277 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005278 int char_length = mapping->get(current, next, chars);
5279 if (char_length == 0) {
5280 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005281 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005282 i++;
5283 } else if (char_length == 1) {
5284 // Common case: converting the letter resulted in one character.
5285 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005286 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005287 has_changed_character = true;
5288 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005289 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005290 // We've assumed that the result would be as long as the
5291 // input but here is a character that converts to several
5292 // characters. No matter, we calculate the exact length
5293 // of the result and try the whole thing again.
5294 //
5295 // Note that this leaves room for optimization. We could just
5296 // memcpy what we already have to the result string. Also,
5297 // the result string is the last object allocated we could
5298 // "realloc" it and probably, in the vast majority of cases,
5299 // extend the existing string to be able to hold the full
5300 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005301 int next_length = 0;
5302 if (has_next) {
5303 next_length = mapping->get(next, 0, chars);
5304 if (next_length == 0) next_length = 1;
5305 }
5306 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005307 while (buffer->has_more()) {
5308 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005309 // NOTE: we use 0 as the next character here because, while
5310 // the next character may affect what a character converts to,
5311 // it does not in any case affect the length of what it convert
5312 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005313 int char_length = mapping->get(current, 0, chars);
5314 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005315 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005316 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005317 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005318 return Failure::OutOfMemoryException();
5319 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005320 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005321 // Try again with the real length.
5322 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005323 } else {
5324 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005325 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005326 i++;
5327 }
5328 has_changed_character = true;
5329 }
5330 current = next;
5331 }
5332 if (has_changed_character) {
5333 return result;
5334 } else {
5335 // If we didn't actually change anything in doing the conversion
5336 // we simple return the result and let the converted string
5337 // become garbage; there is no reason to keep two identical strings
5338 // alive.
5339 return s;
5340 }
5341}
5342
5343
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005344namespace {
5345
lrn@chromium.org303ada72010-10-27 09:33:13 +00005346static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5347
5348
5349// Given a word and two range boundaries returns a word with high bit
5350// set in every byte iff the corresponding input byte was strictly in
5351// the range (m, n). All the other bits in the result are cleared.
5352// This function is only useful when it can be inlined and the
5353// boundaries are statically known.
5354// Requires: all bytes in the input word and the boundaries must be
5355// ascii (less than 0x7F).
5356static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5357 // Every byte in an ascii string is less than or equal to 0x7F.
5358 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5359 // Use strict inequalities since in edge cases the function could be
5360 // further simplified.
5361 ASSERT(0 < m && m < n && n < 0x7F);
5362 // Has high bit set in every w byte less than n.
5363 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5364 // Has high bit set in every w byte greater than m.
5365 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5366 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5367}
5368
5369
5370enum AsciiCaseConversion {
5371 ASCII_TO_LOWER,
5372 ASCII_TO_UPPER
5373};
5374
5375
5376template <AsciiCaseConversion dir>
5377struct FastAsciiConverter {
5378 static bool Convert(char* dst, char* src, int length) {
5379#ifdef DEBUG
5380 char* saved_dst = dst;
5381 char* saved_src = src;
5382#endif
5383 // We rely on the distance between upper and lower case letters
5384 // being a known power of 2.
5385 ASSERT('a' - 'A' == (1 << 5));
5386 // Boundaries for the range of input characters than require conversion.
5387 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5388 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5389 bool changed = false;
5390 char* const limit = src + length;
5391#ifdef V8_HOST_CAN_READ_UNALIGNED
5392 // Process the prefix of the input that requires no conversion one
5393 // (machine) word at a time.
5394 while (src <= limit - sizeof(uintptr_t)) {
5395 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5396 if (AsciiRangeMask(w, lo, hi) != 0) {
5397 changed = true;
5398 break;
5399 }
5400 *reinterpret_cast<uintptr_t*>(dst) = w;
5401 src += sizeof(uintptr_t);
5402 dst += sizeof(uintptr_t);
5403 }
5404 // Process the remainder of the input performing conversion when
5405 // required one word at a time.
5406 while (src <= limit - sizeof(uintptr_t)) {
5407 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5408 uintptr_t m = AsciiRangeMask(w, lo, hi);
5409 // The mask has high (7th) bit set in every byte that needs
5410 // conversion and we know that the distance between cases is
5411 // 1 << 5.
5412 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5413 src += sizeof(uintptr_t);
5414 dst += sizeof(uintptr_t);
5415 }
5416#endif
5417 // Process the last few bytes of the input (or the whole input if
5418 // unaligned access is not supported).
5419 while (src < limit) {
5420 char c = *src;
5421 if (lo < c && c < hi) {
5422 c ^= (1 << 5);
5423 changed = true;
5424 }
5425 *dst = c;
5426 ++src;
5427 ++dst;
5428 }
5429#ifdef DEBUG
5430 CheckConvert(saved_dst, saved_src, length, changed);
5431#endif
5432 return changed;
5433 }
5434
5435#ifdef DEBUG
5436 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5437 bool expected_changed = false;
5438 for (int i = 0; i < length; i++) {
5439 if (dst[i] == src[i]) continue;
5440 expected_changed = true;
5441 if (dir == ASCII_TO_LOWER) {
5442 ASSERT('A' <= src[i] && src[i] <= 'Z');
5443 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5444 } else {
5445 ASSERT(dir == ASCII_TO_UPPER);
5446 ASSERT('a' <= src[i] && src[i] <= 'z');
5447 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5448 }
5449 }
5450 ASSERT(expected_changed == changed);
5451 }
5452#endif
5453};
5454
5455
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005456struct ToLowerTraits {
5457 typedef unibrow::ToLowercase UnibrowConverter;
5458
lrn@chromium.org303ada72010-10-27 09:33:13 +00005459 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005460};
5461
5462
5463struct ToUpperTraits {
5464 typedef unibrow::ToUppercase UnibrowConverter;
5465
lrn@chromium.org303ada72010-10-27 09:33:13 +00005466 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005467};
5468
5469} // namespace
5470
5471
5472template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005473MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005474 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005475 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005476 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005477 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005478 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005479 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005480
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005481 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005482 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005483 if (length == 0) return s;
5484
5485 // Simpler handling of ascii strings.
5486 //
5487 // NOTE: This assumes that the upper/lower case of an ascii
5488 // character is also ascii. This is currently the case, but it
5489 // might break in the future if we implement more context and locale
5490 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005491 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005492 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005493 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005494 if (!maybe_o->ToObject(&o)) return maybe_o;
5495 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005496 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005497 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005498 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005499 return has_changed_character ? result : s;
5500 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005501
lrn@chromium.org303ada72010-10-27 09:33:13 +00005502 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005503 { MaybeObject* maybe_answer =
5504 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005505 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5506 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005507 if (answer->IsSmi()) {
5508 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005509 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005510 ConvertCaseHelper(isolate,
5511 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005512 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5513 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005514 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005515 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005516}
5517
5518
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005519RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005520 return ConvertCase<ToLowerTraits>(
5521 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005522}
5523
5524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005525RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005526 return ConvertCase<ToUpperTraits>(
5527 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005528}
5529
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005530
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005531static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5532 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5533}
5534
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005535
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005536RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005537 NoHandleAllocation ha;
5538 ASSERT(args.length() == 3);
5539
5540 CONVERT_CHECKED(String, s, args[0]);
5541 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5542 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5543
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005544 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005545 int length = s->length();
5546
5547 int left = 0;
5548 if (trimLeft) {
5549 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5550 left++;
5551 }
5552 }
5553
5554 int right = length;
5555 if (trimRight) {
5556 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5557 right--;
5558 }
5559 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005560 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005561}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005562
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005563
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005564template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005565void FindStringIndices(Isolate* isolate,
5566 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005567 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005568 ZoneList<int>* indices,
5569 unsigned int limit) {
5570 ASSERT(limit > 0);
5571 // Collect indices of pattern in subject, and the end-of-string index.
5572 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005573 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005574 int pattern_length = pattern.length();
5575 int index = 0;
5576 while (limit > 0) {
5577 index = search.Search(subject, index);
5578 if (index < 0) return;
5579 indices->Add(index);
5580 index += pattern_length;
5581 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005582 }
5583}
5584
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005586RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005587 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005588 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005589 CONVERT_ARG_CHECKED(String, subject, 0);
5590 CONVERT_ARG_CHECKED(String, pattern, 1);
5591 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5592
5593 int subject_length = subject->length();
5594 int pattern_length = pattern->length();
5595 RUNTIME_ASSERT(pattern_length > 0);
5596
5597 // The limit can be very large (0xffffffffu), but since the pattern
5598 // isn't empty, we can never create more parts than ~half the length
5599 // of the subject.
5600
5601 if (!subject->IsFlat()) FlattenString(subject);
5602
5603 static const int kMaxInitialListCapacity = 16;
5604
danno@chromium.org40cb8782011-05-25 07:58:50 +00005605 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005606
5607 // Find (up to limit) indices of separator and end-of-string in subject
5608 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5609 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005610 if (!pattern->IsFlat()) FlattenString(pattern);
5611
5612 // No allocation block.
5613 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005614 AssertNoAllocation nogc;
5615 if (subject->IsAsciiRepresentation()) {
5616 Vector<const char> subject_vector = subject->ToAsciiVector();
5617 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005618 FindStringIndices(isolate,
5619 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005620 pattern->ToAsciiVector(),
5621 &indices,
5622 limit);
5623 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005624 FindStringIndices(isolate,
5625 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005626 pattern->ToUC16Vector(),
5627 &indices,
5628 limit);
5629 }
5630 } else {
5631 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5632 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005633 FindStringIndices(isolate,
5634 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005635 pattern->ToAsciiVector(),
5636 &indices,
5637 limit);
5638 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005639 FindStringIndices(isolate,
5640 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005641 pattern->ToUC16Vector(),
5642 &indices,
5643 limit);
5644 }
5645 }
5646 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005647
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005648 if (static_cast<uint32_t>(indices.length()) < limit) {
5649 indices.Add(subject_length);
5650 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005651
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005652 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005653
5654 // Create JSArray of substrings separated by separator.
5655 int part_count = indices.length();
5656
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005657 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005658 result->set_length(Smi::FromInt(part_count));
5659
5660 ASSERT(result->HasFastElements());
5661
5662 if (part_count == 1 && indices.at(0) == subject_length) {
5663 FixedArray::cast(result->elements())->set(0, *subject);
5664 return *result;
5665 }
5666
5667 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5668 int part_start = 0;
5669 for (int i = 0; i < part_count; i++) {
5670 HandleScope local_loop_handle;
5671 int part_end = indices.at(i);
5672 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005673 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005674 elements->set(i, *substring);
5675 part_start = part_end + pattern_length;
5676 }
5677
5678 return *result;
5679}
5680
5681
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005682// Copies ascii characters to the given fixed array looking up
5683// one-char strings in the cache. Gives up on the first char that is
5684// not in the cache and fills the remainder with smi zeros. Returns
5685// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005686static int CopyCachedAsciiCharsToArray(Heap* heap,
5687 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005688 FixedArray* elements,
5689 int length) {
5690 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005691 FixedArray* ascii_cache = heap->single_character_string_cache();
5692 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005693 int i;
5694 for (i = 0; i < length; ++i) {
5695 Object* value = ascii_cache->get(chars[i]);
5696 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005697 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005698 elements->set(i, value, SKIP_WRITE_BARRIER);
5699 }
5700 if (i < length) {
5701 ASSERT(Smi::FromInt(0) == 0);
5702 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5703 }
5704#ifdef DEBUG
5705 for (int j = 0; j < length; ++j) {
5706 Object* element = elements->get(j);
5707 ASSERT(element == Smi::FromInt(0) ||
5708 (element->IsString() && String::cast(element)->LooksValid()));
5709 }
5710#endif
5711 return i;
5712}
5713
5714
5715// Converts a String to JSArray.
5716// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005717RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005718 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005719 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005720 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005721 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005722
5723 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005724 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005725
5726 Handle<FixedArray> elements;
5727 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005728 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005729 { MaybeObject* maybe_obj =
5730 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005731 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5732 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005733 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005734
5735 Vector<const char> chars = s->ToAsciiVector();
5736 // Note, this will initialize all elements (not only the prefix)
5737 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005738 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5739 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005740 *elements,
5741 length);
5742
5743 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005744 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5745 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005746 }
5747 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005748 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005749 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005750 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5751 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005752 }
5753 }
5754
5755#ifdef DEBUG
5756 for (int i = 0; i < length; ++i) {
5757 ASSERT(String::cast(elements->get(i))->length() == 1);
5758 }
5759#endif
5760
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005761 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005762}
5763
5764
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005765RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005766 NoHandleAllocation ha;
5767 ASSERT(args.length() == 1);
5768 CONVERT_CHECKED(String, value, args[0]);
5769 return value->ToObject();
5770}
5771
5772
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005773bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005774 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005775 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005776 return char_length == 0;
5777}
5778
5779
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005780RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005781 NoHandleAllocation ha;
5782 ASSERT(args.length() == 1);
5783
5784 Object* number = args[0];
5785 RUNTIME_ASSERT(number->IsNumber());
5786
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005787 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005788}
5789
5790
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005791RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005792 NoHandleAllocation ha;
5793 ASSERT(args.length() == 1);
5794
5795 Object* number = args[0];
5796 RUNTIME_ASSERT(number->IsNumber());
5797
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005798 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005799}
5800
5801
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005802RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005803 NoHandleAllocation ha;
5804 ASSERT(args.length() == 1);
5805
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005806 CONVERT_DOUBLE_CHECKED(number, args[0]);
5807
5808 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5809 if (number > 0 && number <= Smi::kMaxValue) {
5810 return Smi::FromInt(static_cast<int>(number));
5811 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005812 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005813}
5814
5815
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005816RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005817 NoHandleAllocation ha;
5818 ASSERT(args.length() == 1);
5819
5820 CONVERT_DOUBLE_CHECKED(number, args[0]);
5821
5822 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5823 if (number > 0 && number <= Smi::kMaxValue) {
5824 return Smi::FromInt(static_cast<int>(number));
5825 }
5826
5827 double double_value = DoubleToInteger(number);
5828 // Map both -0 and +0 to +0.
5829 if (double_value == 0) double_value = 0;
5830
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005831 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005832}
5833
5834
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005835RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005836 NoHandleAllocation ha;
5837 ASSERT(args.length() == 1);
5838
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005839 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005840 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005841}
5842
5843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005844RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005845 NoHandleAllocation ha;
5846 ASSERT(args.length() == 1);
5847
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005848 CONVERT_DOUBLE_CHECKED(number, args[0]);
5849
5850 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5851 if (number > 0 && number <= Smi::kMaxValue) {
5852 return Smi::FromInt(static_cast<int>(number));
5853 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005854 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005855}
5856
5857
ager@chromium.org870a0b62008-11-04 11:43:05 +00005858// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5859// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005860RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005861 NoHandleAllocation ha;
5862 ASSERT(args.length() == 1);
5863
5864 Object* obj = args[0];
5865 if (obj->IsSmi()) {
5866 return obj;
5867 }
5868 if (obj->IsHeapNumber()) {
5869 double value = HeapNumber::cast(obj)->value();
5870 int int_value = FastD2I(value);
5871 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5872 return Smi::FromInt(int_value);
5873 }
5874 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005875 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005876}
5877
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005878
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005879RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005880 NoHandleAllocation ha;
5881 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005882 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005883}
5884
5885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005886RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005887 NoHandleAllocation ha;
5888 ASSERT(args.length() == 2);
5889
5890 CONVERT_DOUBLE_CHECKED(x, args[0]);
5891 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005892 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005893}
5894
5895
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005896RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005897 NoHandleAllocation ha;
5898 ASSERT(args.length() == 2);
5899
5900 CONVERT_DOUBLE_CHECKED(x, args[0]);
5901 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005902 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005903}
5904
5905
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005906RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005907 NoHandleAllocation ha;
5908 ASSERT(args.length() == 2);
5909
5910 CONVERT_DOUBLE_CHECKED(x, args[0]);
5911 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005912 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005913}
5914
5915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005916RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005917 NoHandleAllocation ha;
5918 ASSERT(args.length() == 1);
5919
5920 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005921 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005922}
5923
5924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005925RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005926 NoHandleAllocation ha;
5927 ASSERT(args.length() == 0);
5928
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005929 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005930}
5931
5932
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005933RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005934 NoHandleAllocation ha;
5935 ASSERT(args.length() == 2);
5936
5937 CONVERT_DOUBLE_CHECKED(x, args[0]);
5938 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005939 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005940}
5941
5942
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005943RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005944 NoHandleAllocation ha;
5945 ASSERT(args.length() == 2);
5946
5947 CONVERT_DOUBLE_CHECKED(x, args[0]);
5948 CONVERT_DOUBLE_CHECKED(y, args[1]);
5949
ager@chromium.org3811b432009-10-28 14:53:37 +00005950 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005951 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005952 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005953}
5954
5955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005956RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005957 NoHandleAllocation ha;
5958 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005959 CONVERT_CHECKED(String, str1, args[0]);
5960 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005961 isolate->counters()->string_add_runtime()->Increment();
5962 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005963}
5964
5965
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005966template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005967static inline void StringBuilderConcatHelper(String* special,
5968 sinkchar* sink,
5969 FixedArray* fixed_array,
5970 int array_length) {
5971 int position = 0;
5972 for (int i = 0; i < array_length; i++) {
5973 Object* element = fixed_array->get(i);
5974 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005975 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005976 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005977 int pos;
5978 int len;
5979 if (encoded_slice > 0) {
5980 // Position and length encoded in one smi.
5981 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5982 len = StringBuilderSubstringLength::decode(encoded_slice);
5983 } else {
5984 // Position and length encoded in two smis.
5985 Object* obj = fixed_array->get(++i);
5986 ASSERT(obj->IsSmi());
5987 pos = Smi::cast(obj)->value();
5988 len = -encoded_slice;
5989 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005990 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005991 sink + position,
5992 pos,
5993 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005994 position += len;
5995 } else {
5996 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005997 int element_length = string->length();
5998 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005999 position += element_length;
6000 }
6001 }
6002}
6003
6004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006005RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006006 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006007 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006008 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006009 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006010 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006011 return Failure::OutOfMemoryException();
6012 }
6013 int array_length = Smi::cast(args[1])->value();
6014 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006015
6016 // This assumption is used by the slice encoding in one or two smis.
6017 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6018
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006019 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006020 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006021 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006022 }
6023 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006024 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006025 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006026 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006027
6028 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006029 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006030 } else if (array_length == 1) {
6031 Object* first = fixed_array->get(0);
6032 if (first->IsString()) return first;
6033 }
6034
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006035 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006036 int position = 0;
6037 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006038 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006039 Object* elt = fixed_array->get(i);
6040 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006041 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006042 int smi_value = Smi::cast(elt)->value();
6043 int pos;
6044 int len;
6045 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006046 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006047 pos = StringBuilderSubstringPosition::decode(smi_value);
6048 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006049 } else {
6050 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006051 len = -smi_value;
6052 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006053 i++;
6054 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006055 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006056 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006057 Object* next_smi = fixed_array->get(i);
6058 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006059 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006060 }
6061 pos = Smi::cast(next_smi)->value();
6062 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006063 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006064 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006065 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006066 ASSERT(pos >= 0);
6067 ASSERT(len >= 0);
6068 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006069 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006070 }
6071 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006072 } else if (elt->IsString()) {
6073 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006074 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006075 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006076 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006077 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006078 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006079 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006080 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006081 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006082 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006083 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006084 return Failure::OutOfMemoryException();
6085 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006086 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006087 }
6088
6089 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006090 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006091
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006092 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006093 { MaybeObject* maybe_object =
6094 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006095 if (!maybe_object->ToObject(&object)) return maybe_object;
6096 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006097 SeqAsciiString* answer = SeqAsciiString::cast(object);
6098 StringBuilderConcatHelper(special,
6099 answer->GetChars(),
6100 fixed_array,
6101 array_length);
6102 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006103 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006104 { MaybeObject* maybe_object =
6105 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006106 if (!maybe_object->ToObject(&object)) return maybe_object;
6107 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006108 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6109 StringBuilderConcatHelper(special,
6110 answer->GetChars(),
6111 fixed_array,
6112 array_length);
6113 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006114 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006115}
6116
6117
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006118RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006119 NoHandleAllocation ha;
6120 ASSERT(args.length() == 3);
6121 CONVERT_CHECKED(JSArray, array, args[0]);
6122 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006123 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006124 return Failure::OutOfMemoryException();
6125 }
6126 int array_length = Smi::cast(args[1])->value();
6127 CONVERT_CHECKED(String, separator, args[2]);
6128
6129 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006130 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006131 }
6132 FixedArray* fixed_array = FixedArray::cast(array->elements());
6133 if (fixed_array->length() < array_length) {
6134 array_length = fixed_array->length();
6135 }
6136
6137 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006138 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006139 } else if (array_length == 1) {
6140 Object* first = fixed_array->get(0);
6141 if (first->IsString()) return first;
6142 }
6143
6144 int separator_length = separator->length();
6145 int max_nof_separators =
6146 (String::kMaxLength + separator_length - 1) / separator_length;
6147 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006148 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006149 return Failure::OutOfMemoryException();
6150 }
6151 int length = (array_length - 1) * separator_length;
6152 for (int i = 0; i < array_length; i++) {
6153 Object* element_obj = fixed_array->get(i);
6154 if (!element_obj->IsString()) {
6155 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006156 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006157 }
6158 String* element = String::cast(element_obj);
6159 int increment = element->length();
6160 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006161 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006162 return Failure::OutOfMemoryException();
6163 }
6164 length += increment;
6165 }
6166
6167 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006168 { MaybeObject* maybe_object =
6169 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006170 if (!maybe_object->ToObject(&object)) return maybe_object;
6171 }
6172 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6173
6174 uc16* sink = answer->GetChars();
6175#ifdef DEBUG
6176 uc16* end = sink + length;
6177#endif
6178
6179 String* first = String::cast(fixed_array->get(0));
6180 int first_length = first->length();
6181 String::WriteToFlat(first, sink, 0, first_length);
6182 sink += first_length;
6183
6184 for (int i = 1; i < array_length; i++) {
6185 ASSERT(sink + separator_length <= end);
6186 String::WriteToFlat(separator, sink, 0, separator_length);
6187 sink += separator_length;
6188
6189 String* element = String::cast(fixed_array->get(i));
6190 int element_length = element->length();
6191 ASSERT(sink + element_length <= end);
6192 String::WriteToFlat(element, sink, 0, element_length);
6193 sink += element_length;
6194 }
6195 ASSERT(sink == end);
6196
6197 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6198 return answer;
6199}
6200
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006201template <typename Char>
6202static void JoinSparseArrayWithSeparator(FixedArray* elements,
6203 int elements_length,
6204 uint32_t array_length,
6205 String* separator,
6206 Vector<Char> buffer) {
6207 int previous_separator_position = 0;
6208 int separator_length = separator->length();
6209 int cursor = 0;
6210 for (int i = 0; i < elements_length; i += 2) {
6211 int position = NumberToInt32(elements->get(i));
6212 String* string = String::cast(elements->get(i + 1));
6213 int string_length = string->length();
6214 if (string->length() > 0) {
6215 while (previous_separator_position < position) {
6216 String::WriteToFlat<Char>(separator, &buffer[cursor],
6217 0, separator_length);
6218 cursor += separator_length;
6219 previous_separator_position++;
6220 }
6221 String::WriteToFlat<Char>(string, &buffer[cursor],
6222 0, string_length);
6223 cursor += string->length();
6224 }
6225 }
6226 if (separator_length > 0) {
6227 // Array length must be representable as a signed 32-bit number,
6228 // otherwise the total string length would have been too large.
6229 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6230 int last_array_index = static_cast<int>(array_length - 1);
6231 while (previous_separator_position < last_array_index) {
6232 String::WriteToFlat<Char>(separator, &buffer[cursor],
6233 0, separator_length);
6234 cursor += separator_length;
6235 previous_separator_position++;
6236 }
6237 }
6238 ASSERT(cursor <= buffer.length());
6239}
6240
6241
6242RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6243 NoHandleAllocation ha;
6244 ASSERT(args.length() == 3);
6245 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6246 RUNTIME_ASSERT(elements_array->HasFastElements());
6247 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6248 CONVERT_CHECKED(String, separator, args[2]);
6249 // elements_array is fast-mode JSarray of alternating positions
6250 // (increasing order) and strings.
6251 // array_length is length of original array (used to add separators);
6252 // separator is string to put between elements. Assumed to be non-empty.
6253
6254 // Find total length of join result.
6255 int string_length = 0;
6256 bool is_ascii = true;
6257 int max_string_length = SeqAsciiString::kMaxLength;
6258 bool overflow = false;
6259 CONVERT_NUMBER_CHECKED(int, elements_length,
6260 Int32, elements_array->length());
6261 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6262 FixedArray* elements = FixedArray::cast(elements_array->elements());
6263 for (int i = 0; i < elements_length; i += 2) {
6264 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6265 CONVERT_CHECKED(String, string, elements->get(i + 1));
6266 int length = string->length();
6267 if (is_ascii && !string->IsAsciiRepresentation()) {
6268 is_ascii = false;
6269 max_string_length = SeqTwoByteString::kMaxLength;
6270 }
6271 if (length > max_string_length ||
6272 max_string_length - length < string_length) {
6273 overflow = true;
6274 break;
6275 }
6276 string_length += length;
6277 }
6278 int separator_length = separator->length();
6279 if (!overflow && separator_length > 0) {
6280 if (array_length <= 0x7fffffffu) {
6281 int separator_count = static_cast<int>(array_length) - 1;
6282 int remaining_length = max_string_length - string_length;
6283 if ((remaining_length / separator_length) >= separator_count) {
6284 string_length += separator_length * (array_length - 1);
6285 } else {
6286 // Not room for the separators within the maximal string length.
6287 overflow = true;
6288 }
6289 } else {
6290 // Nonempty separator and at least 2^31-1 separators necessary
6291 // means that the string is too large to create.
6292 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6293 overflow = true;
6294 }
6295 }
6296 if (overflow) {
6297 // Throw OutOfMemory exception for creating too large a string.
6298 V8::FatalProcessOutOfMemory("Array join result too large.");
6299 }
6300
6301 if (is_ascii) {
6302 MaybeObject* result_allocation =
6303 isolate->heap()->AllocateRawAsciiString(string_length);
6304 if (result_allocation->IsFailure()) return result_allocation;
6305 SeqAsciiString* result_string =
6306 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6307 JoinSparseArrayWithSeparator<char>(elements,
6308 elements_length,
6309 array_length,
6310 separator,
6311 Vector<char>(result_string->GetChars(),
6312 string_length));
6313 return result_string;
6314 } else {
6315 MaybeObject* result_allocation =
6316 isolate->heap()->AllocateRawTwoByteString(string_length);
6317 if (result_allocation->IsFailure()) return result_allocation;
6318 SeqTwoByteString* result_string =
6319 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6320 JoinSparseArrayWithSeparator<uc16>(elements,
6321 elements_length,
6322 array_length,
6323 separator,
6324 Vector<uc16>(result_string->GetChars(),
6325 string_length));
6326 return result_string;
6327 }
6328}
6329
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006330
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006331RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006332 NoHandleAllocation ha;
6333 ASSERT(args.length() == 2);
6334
6335 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6336 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006337 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006338}
6339
6340
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006341RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006342 NoHandleAllocation ha;
6343 ASSERT(args.length() == 2);
6344
6345 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6346 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006347 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006348}
6349
6350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006351RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006352 NoHandleAllocation ha;
6353 ASSERT(args.length() == 2);
6354
6355 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6356 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006357 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006358}
6359
6360
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006361RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006362 NoHandleAllocation ha;
6363 ASSERT(args.length() == 1);
6364
6365 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006366 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006367}
6368
6369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006370RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006371 NoHandleAllocation ha;
6372 ASSERT(args.length() == 2);
6373
6374 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6375 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006376 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006377}
6378
6379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006380RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006381 NoHandleAllocation ha;
6382 ASSERT(args.length() == 2);
6383
6384 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6385 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006386 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006387}
6388
6389
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006390RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006391 NoHandleAllocation ha;
6392 ASSERT(args.length() == 2);
6393
6394 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6395 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006396 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006397}
6398
6399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006400RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006401 NoHandleAllocation ha;
6402 ASSERT(args.length() == 2);
6403
6404 CONVERT_DOUBLE_CHECKED(x, args[0]);
6405 CONVERT_DOUBLE_CHECKED(y, args[1]);
6406 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6407 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6408 if (x == y) return Smi::FromInt(EQUAL);
6409 Object* result;
6410 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6411 result = Smi::FromInt(EQUAL);
6412 } else {
6413 result = Smi::FromInt(NOT_EQUAL);
6414 }
6415 return result;
6416}
6417
6418
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006419RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006420 NoHandleAllocation ha;
6421 ASSERT(args.length() == 2);
6422
6423 CONVERT_CHECKED(String, x, args[0]);
6424 CONVERT_CHECKED(String, y, args[1]);
6425
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006426 bool not_equal = !x->Equals(y);
6427 // This is slightly convoluted because the value that signifies
6428 // equality is 0 and inequality is 1 so we have to negate the result
6429 // from String::Equals.
6430 ASSERT(not_equal == 0 || not_equal == 1);
6431 STATIC_CHECK(EQUAL == 0);
6432 STATIC_CHECK(NOT_EQUAL == 1);
6433 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006434}
6435
6436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006437RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006438 NoHandleAllocation ha;
6439 ASSERT(args.length() == 3);
6440
6441 CONVERT_DOUBLE_CHECKED(x, args[0]);
6442 CONVERT_DOUBLE_CHECKED(y, args[1]);
6443 if (isnan(x) || isnan(y)) return args[2];
6444 if (x == y) return Smi::FromInt(EQUAL);
6445 if (isless(x, y)) return Smi::FromInt(LESS);
6446 return Smi::FromInt(GREATER);
6447}
6448
6449
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006450// Compare two Smis as if they were converted to strings and then
6451// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006452RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006453 NoHandleAllocation ha;
6454 ASSERT(args.length() == 2);
6455
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006456 // Extract the integer values from the Smis.
6457 CONVERT_CHECKED(Smi, x, args[0]);
6458 CONVERT_CHECKED(Smi, y, args[1]);
6459 int x_value = x->value();
6460 int y_value = y->value();
6461
6462 // If the integers are equal so are the string representations.
6463 if (x_value == y_value) return Smi::FromInt(EQUAL);
6464
6465 // If one of the integers are zero the normal integer order is the
6466 // same as the lexicographic order of the string representations.
6467 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6468
ager@chromium.org32912102009-01-16 10:38:43 +00006469 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006470 // smallest because the char code of '-' is less than the char code
6471 // of any digit. Otherwise, we make both values positive.
6472 if (x_value < 0 || y_value < 0) {
6473 if (y_value >= 0) return Smi::FromInt(LESS);
6474 if (x_value >= 0) return Smi::FromInt(GREATER);
6475 x_value = -x_value;
6476 y_value = -y_value;
6477 }
6478
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006479 // Arrays for the individual characters of the two Smis. Smis are
6480 // 31 bit integers and 10 decimal digits are therefore enough.
6481 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6482 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6483 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6484
6485
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006486 // Convert the integers to arrays of their decimal digits.
6487 int x_index = 0;
6488 int y_index = 0;
6489 while (x_value > 0) {
6490 x_elms[x_index++] = x_value % 10;
6491 x_value /= 10;
6492 }
6493 while (y_value > 0) {
6494 y_elms[y_index++] = y_value % 10;
6495 y_value /= 10;
6496 }
6497
6498 // Loop through the arrays of decimal digits finding the first place
6499 // where they differ.
6500 while (--x_index >= 0 && --y_index >= 0) {
6501 int diff = x_elms[x_index] - y_elms[y_index];
6502 if (diff != 0) return Smi::FromInt(diff);
6503 }
6504
6505 // If one array is a suffix of the other array, the longest array is
6506 // the representation of the largest of the Smis in the
6507 // lexicographic ordering.
6508 return Smi::FromInt(x_index - y_index);
6509}
6510
6511
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006512static Object* StringInputBufferCompare(RuntimeState* state,
6513 String* x,
6514 String* y) {
6515 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6516 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006517 bufx.Reset(x);
6518 bufy.Reset(y);
6519 while (bufx.has_more() && bufy.has_more()) {
6520 int d = bufx.GetNext() - bufy.GetNext();
6521 if (d < 0) return Smi::FromInt(LESS);
6522 else if (d > 0) return Smi::FromInt(GREATER);
6523 }
6524
6525 // x is (non-trivial) prefix of y:
6526 if (bufy.has_more()) return Smi::FromInt(LESS);
6527 // y is prefix of x:
6528 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6529}
6530
6531
6532static Object* FlatStringCompare(String* x, String* y) {
6533 ASSERT(x->IsFlat());
6534 ASSERT(y->IsFlat());
6535 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6536 int prefix_length = x->length();
6537 if (y->length() < prefix_length) {
6538 prefix_length = y->length();
6539 equal_prefix_result = Smi::FromInt(GREATER);
6540 } else if (y->length() > prefix_length) {
6541 equal_prefix_result = Smi::FromInt(LESS);
6542 }
6543 int r;
6544 if (x->IsAsciiRepresentation()) {
6545 Vector<const char> x_chars = x->ToAsciiVector();
6546 if (y->IsAsciiRepresentation()) {
6547 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006548 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006549 } else {
6550 Vector<const uc16> y_chars = y->ToUC16Vector();
6551 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6552 }
6553 } else {
6554 Vector<const uc16> x_chars = x->ToUC16Vector();
6555 if (y->IsAsciiRepresentation()) {
6556 Vector<const char> y_chars = y->ToAsciiVector();
6557 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6558 } else {
6559 Vector<const uc16> y_chars = y->ToUC16Vector();
6560 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6561 }
6562 }
6563 Object* result;
6564 if (r == 0) {
6565 result = equal_prefix_result;
6566 } else {
6567 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6568 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006569 ASSERT(result ==
6570 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006571 return result;
6572}
6573
6574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006575RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006576 NoHandleAllocation ha;
6577 ASSERT(args.length() == 2);
6578
6579 CONVERT_CHECKED(String, x, args[0]);
6580 CONVERT_CHECKED(String, y, args[1]);
6581
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006582 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006583
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006584 // A few fast case tests before we flatten.
6585 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006586 if (y->length() == 0) {
6587 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006588 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006589 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006590 return Smi::FromInt(LESS);
6591 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006592
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006593 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006594 if (d < 0) return Smi::FromInt(LESS);
6595 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006596
lrn@chromium.org303ada72010-10-27 09:33:13 +00006597 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006598 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006599 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6600 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006601 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006602 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6603 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006604
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006605 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006606 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006607}
6608
6609
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006610RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006611 NoHandleAllocation ha;
6612 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006613 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006614
6615 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006616 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006617}
6618
6619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006620RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006621 NoHandleAllocation ha;
6622 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006623 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006624
6625 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006626 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006627}
6628
6629
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006630RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006631 NoHandleAllocation ha;
6632 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006633 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006634
6635 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006636 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006637}
6638
6639
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006640static const double kPiDividedBy4 = 0.78539816339744830962;
6641
6642
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006643RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006644 NoHandleAllocation ha;
6645 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006646 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006647
6648 CONVERT_DOUBLE_CHECKED(x, args[0]);
6649 CONVERT_DOUBLE_CHECKED(y, args[1]);
6650 double result;
6651 if (isinf(x) && isinf(y)) {
6652 // Make sure that the result in case of two infinite arguments
6653 // is a multiple of Pi / 4. The sign of the result is determined
6654 // by the first argument (x) and the sign of the second argument
6655 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006656 int multiplier = (x < 0) ? -1 : 1;
6657 if (y < 0) multiplier *= 3;
6658 result = multiplier * kPiDividedBy4;
6659 } else {
6660 result = atan2(x, y);
6661 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006662 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006663}
6664
6665
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006666RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006667 NoHandleAllocation ha;
6668 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006669 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006670
6671 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006672 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006673}
6674
6675
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006676RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677 NoHandleAllocation ha;
6678 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006679 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006680
6681 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006682 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006683}
6684
6685
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006686RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006687 NoHandleAllocation ha;
6688 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006689 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006690
6691 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006692 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006693}
6694
6695
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006696RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006697 NoHandleAllocation ha;
6698 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006699 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006700
6701 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006702 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006703}
6704
6705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006706RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006707 NoHandleAllocation ha;
6708 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006709 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006710
6711 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006712 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006713}
6714
6715
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006716RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006717 NoHandleAllocation ha;
6718 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006719 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006720
6721 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006722
6723 // If the second argument is a smi, it is much faster to call the
6724 // custom powi() function than the generic pow().
6725 if (args[1]->IsSmi()) {
6726 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006727 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006728 }
6729
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006730 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006731 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006732}
6733
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006734// Fast version of Math.pow if we know that y is not an integer and
6735// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006736RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006737 NoHandleAllocation ha;
6738 ASSERT(args.length() == 2);
6739 CONVERT_DOUBLE_CHECKED(x, args[0]);
6740 CONVERT_DOUBLE_CHECKED(y, args[1]);
6741 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006742 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006743 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006745 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006746 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006747 }
6748}
6749
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006750
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006751RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006752 NoHandleAllocation ha;
6753 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006754 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006755
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006756 if (!args[0]->IsHeapNumber()) {
6757 // Must be smi. Return the argument unchanged for all the other types
6758 // to make fuzz-natives test happy.
6759 return args[0];
6760 }
6761
6762 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6763
6764 double value = number->value();
6765 int exponent = number->get_exponent();
6766 int sign = number->get_sign();
6767
danno@chromium.org160a7b02011-04-18 15:51:38 +00006768 if (exponent < -1) {
6769 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6770 if (sign) return isolate->heap()->minus_zero_value();
6771 return Smi::FromInt(0);
6772 }
6773
6774 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6775 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6776 // agument holds for 32-bit smis).
6777 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006778 return Smi::FromInt(static_cast<int>(value + 0.5));
6779 }
6780
6781 // If the magnitude is big enough, there's no place for fraction part. If we
6782 // try to add 0.5 to this number, 1.0 will be added instead.
6783 if (exponent >= 52) {
6784 return number;
6785 }
6786
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006787 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006788
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006789 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006790 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006791}
6792
6793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006794RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006795 NoHandleAllocation ha;
6796 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006797 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006798
6799 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006800 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006801}
6802
6803
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006804RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006805 NoHandleAllocation ha;
6806 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006807 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006808
6809 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006810 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006811}
6812
6813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006814RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006815 NoHandleAllocation ha;
6816 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006817 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006818
6819 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006820 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006821}
6822
6823
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006824static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006825 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6826 181, 212, 243, 273, 304, 334};
6827 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6828 182, 213, 244, 274, 305, 335};
6829
6830 year += month / 12;
6831 month %= 12;
6832 if (month < 0) {
6833 year--;
6834 month += 12;
6835 }
6836
6837 ASSERT(month >= 0);
6838 ASSERT(month < 12);
6839
6840 // year_delta is an arbitrary number such that:
6841 // a) year_delta = -1 (mod 400)
6842 // b) year + year_delta > 0 for years in the range defined by
6843 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6844 // Jan 1 1970. This is required so that we don't run into integer
6845 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006846 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006847 // operations.
6848 static const int year_delta = 399999;
6849 static const int base_day = 365 * (1970 + year_delta) +
6850 (1970 + year_delta) / 4 -
6851 (1970 + year_delta) / 100 +
6852 (1970 + year_delta) / 400;
6853
6854 int year1 = year + year_delta;
6855 int day_from_year = 365 * year1 +
6856 year1 / 4 -
6857 year1 / 100 +
6858 year1 / 400 -
6859 base_day;
6860
6861 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006862 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006863 }
6864
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006865 return day_from_year + day_from_month_leap[month] + day - 1;
6866}
6867
6868
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006869RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006870 NoHandleAllocation ha;
6871 ASSERT(args.length() == 3);
6872
6873 CONVERT_SMI_CHECKED(year, args[0]);
6874 CONVERT_SMI_CHECKED(month, args[1]);
6875 CONVERT_SMI_CHECKED(date, args[2]);
6876
6877 return Smi::FromInt(MakeDay(year, month, date));
6878}
6879
6880
6881static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6882static const int kDaysIn4Years = 4 * 365 + 1;
6883static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6884static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6885static const int kDays1970to2000 = 30 * 365 + 7;
6886static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6887 kDays1970to2000;
6888static const int kYearsOffset = 400000;
6889
6890static const char kDayInYear[] = {
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, 29, 30, 31,
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,
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, 31,
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,
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, 31,
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,
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, 31,
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,
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, 31,
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,
6913 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6914 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6915
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, 29, 30, 31,
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,
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, 31,
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,
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, 31,
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,
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, 31,
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,
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, 31,
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,
6938 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6939 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6940
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, 30, 31,
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,
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, 31,
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,
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, 31,
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,
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, 31,
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,
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, 31,
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,
6963 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6964 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6965
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, 29, 30, 31,
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,
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, 31,
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,
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, 31,
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,
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, 31,
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,
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, 31,
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,
6988 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6989 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6990
6991static const char kMonthInYear[] = {
6992 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,
6993 0, 0, 0, 0, 0, 0,
6994 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,
6995 1, 1, 1,
6996 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,
6997 2, 2, 2, 2, 2, 2,
6998 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,
6999 3, 3, 3, 3, 3,
7000 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,
7001 4, 4, 4, 4, 4, 4,
7002 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,
7003 5, 5, 5, 5, 5,
7004 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,
7005 6, 6, 6, 6, 6, 6,
7006 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,
7007 7, 7, 7, 7, 7, 7,
7008 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,
7009 8, 8, 8, 8, 8,
7010 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,
7011 9, 9, 9, 9, 9, 9,
7012 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7013 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7014 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7015 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7016
7017 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,
7018 0, 0, 0, 0, 0, 0,
7019 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,
7020 1, 1, 1,
7021 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,
7022 2, 2, 2, 2, 2, 2,
7023 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,
7024 3, 3, 3, 3, 3,
7025 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,
7026 4, 4, 4, 4, 4, 4,
7027 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,
7028 5, 5, 5, 5, 5,
7029 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,
7030 6, 6, 6, 6, 6, 6,
7031 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,
7032 7, 7, 7, 7, 7, 7,
7033 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,
7034 8, 8, 8, 8, 8,
7035 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,
7036 9, 9, 9, 9, 9, 9,
7037 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7038 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7039 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7040 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7041
7042 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,
7043 0, 0, 0, 0, 0, 0,
7044 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,
7045 1, 1, 1, 1,
7046 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,
7047 2, 2, 2, 2, 2, 2,
7048 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,
7049 3, 3, 3, 3, 3,
7050 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,
7051 4, 4, 4, 4, 4, 4,
7052 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,
7053 5, 5, 5, 5, 5,
7054 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,
7055 6, 6, 6, 6, 6, 6,
7056 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,
7057 7, 7, 7, 7, 7, 7,
7058 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,
7059 8, 8, 8, 8, 8,
7060 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,
7061 9, 9, 9, 9, 9, 9,
7062 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7063 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7064 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7065 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7066
7067 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,
7068 0, 0, 0, 0, 0, 0,
7069 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,
7070 1, 1, 1,
7071 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,
7072 2, 2, 2, 2, 2, 2,
7073 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,
7074 3, 3, 3, 3, 3,
7075 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,
7076 4, 4, 4, 4, 4, 4,
7077 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,
7078 5, 5, 5, 5, 5,
7079 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,
7080 6, 6, 6, 6, 6, 6,
7081 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,
7082 7, 7, 7, 7, 7, 7,
7083 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,
7084 8, 8, 8, 8, 8,
7085 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,
7086 9, 9, 9, 9, 9, 9,
7087 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7088 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7089 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7090 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7091
7092
7093// This function works for dates from 1970 to 2099.
7094static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007095 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007096#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007097 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007098#endif
7099
7100 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7101 date %= kDaysIn4Years;
7102
7103 month = kMonthInYear[date];
7104 day = kDayInYear[date];
7105
7106 ASSERT(MakeDay(year, month, day) == save_date);
7107}
7108
7109
7110static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007111 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007112#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007113 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007114#endif
7115
7116 date += kDaysOffset;
7117 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7118 date %= kDaysIn400Years;
7119
7120 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7121
7122 date--;
7123 int yd1 = date / kDaysIn100Years;
7124 date %= kDaysIn100Years;
7125 year += 100 * yd1;
7126
7127 date++;
7128 int yd2 = date / kDaysIn4Years;
7129 date %= kDaysIn4Years;
7130 year += 4 * yd2;
7131
7132 date--;
7133 int yd3 = date / 365;
7134 date %= 365;
7135 year += yd3;
7136
7137 bool is_leap = (!yd1 || yd2) && !yd3;
7138
7139 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007140 ASSERT(is_leap || (date >= 0));
7141 ASSERT((date < 365) || (is_leap && (date < 366)));
7142 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7143 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7144 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007145
7146 if (is_leap) {
7147 day = kDayInYear[2*365 + 1 + date];
7148 month = kMonthInYear[2*365 + 1 + date];
7149 } else {
7150 day = kDayInYear[date];
7151 month = kMonthInYear[date];
7152 }
7153
7154 ASSERT(MakeDay(year, month, day) == save_date);
7155}
7156
7157
7158static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007159 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007160 if (date >= 0 && date < 32 * kDaysIn4Years) {
7161 DateYMDFromTimeAfter1970(date, year, month, day);
7162 } else {
7163 DateYMDFromTimeSlow(date, year, month, day);
7164 }
7165}
7166
7167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007168RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007169 NoHandleAllocation ha;
7170 ASSERT(args.length() == 2);
7171
7172 CONVERT_DOUBLE_CHECKED(t, args[0]);
7173 CONVERT_CHECKED(JSArray, res_array, args[1]);
7174
7175 int year, month, day;
7176 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7177
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007178 RUNTIME_ASSERT(res_array->elements()->map() ==
7179 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007180 FixedArray* elms = FixedArray::cast(res_array->elements());
7181 RUNTIME_ASSERT(elms->length() == 3);
7182
7183 elms->set(0, Smi::FromInt(year));
7184 elms->set(1, Smi::FromInt(month));
7185 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007186
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007187 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007188}
7189
7190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007191RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007192 NoHandleAllocation ha;
7193 ASSERT(args.length() == 3);
7194
7195 JSFunction* callee = JSFunction::cast(args[0]);
7196 Object** parameters = reinterpret_cast<Object**>(args[1]);
7197 const int length = Smi::cast(args[2])->value();
7198
lrn@chromium.org303ada72010-10-27 09:33:13 +00007199 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007200 { MaybeObject* maybe_result =
7201 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007202 if (!maybe_result->ToObject(&result)) return maybe_result;
7203 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007204 // Allocate the elements if needed.
7205 if (length > 0) {
7206 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007207 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007208 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007209 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7210 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007211
7212 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007213 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007214 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007215 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007216
7217 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007218 for (int i = 0; i < length; i++) {
7219 array->set(i, *--parameters, mode);
7220 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007221 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007222 }
7223 return result;
7224}
7225
7226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007227RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007228 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007229 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007230 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007231 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007232 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007233
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007234 // Allocate global closures in old space and allocate local closures
7235 // in new space. Additionally pretenure closures that are assigned
7236 // directly to properties.
7237 pretenure = pretenure || (context->global_context() == *context);
7238 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007239 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007240 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7241 context,
7242 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007243 return *result;
7244}
7245
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007246
7247static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7248 int* total_argc) {
7249 // Find frame containing arguments passed to the caller.
7250 JavaScriptFrameIterator it;
7251 JavaScriptFrame* frame = it.frame();
7252 List<JSFunction*> functions(2);
7253 frame->GetFunctions(&functions);
7254 if (functions.length() > 1) {
7255 int inlined_frame_index = functions.length() - 1;
7256 JSFunction* inlined_function = functions[inlined_frame_index];
7257 int args_count = inlined_function->shared()->formal_parameter_count();
7258 ScopedVector<SlotRef> args_slots(args_count);
7259 SlotRef::ComputeSlotMappingForArguments(frame,
7260 inlined_frame_index,
7261 &args_slots);
7262
7263 *total_argc = bound_argc + args_count;
7264 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7265 for (int i = 0; i < args_count; i++) {
7266 Handle<Object> val = args_slots[i].GetValue();
7267 param_data[bound_argc + i] = val.location();
7268 }
7269 return param_data;
7270 } else {
7271 it.AdvanceToArgumentsFrame();
7272 frame = it.frame();
7273 int args_count = frame->ComputeParametersCount();
7274
7275 *total_argc = bound_argc + args_count;
7276 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7277 for (int i = 0; i < args_count; i++) {
7278 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7279 param_data[bound_argc + i] = val.location();
7280 }
7281 return param_data;
7282 }
7283}
7284
7285
7286RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007287 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007288 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007289 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007290 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007291
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007292 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007293 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007294 int bound_argc = 0;
7295 if (!args[1]->IsNull()) {
7296 CONVERT_ARG_CHECKED(JSArray, params, 1);
7297 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007298 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007299 bound_argc = Smi::cast(params->length())->value();
7300 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007301
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007302 int total_argc = 0;
7303 SmartPointer<Object**> param_data =
7304 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007305 for (int i = 0; i < bound_argc; i++) {
7306 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007307 param_data[i] = val.location();
7308 }
7309
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007310 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007311 Handle<Object> result =
7312 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007313 if (exception) {
7314 return Failure::Exception();
7315 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007316
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007317 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007318 return *result;
7319}
7320
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007322static void TrySettingInlineConstructStub(Isolate* isolate,
7323 Handle<JSFunction> function) {
7324 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007325 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007326 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007327 }
7328 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007329 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007330 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007331 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007332 function->shared()->set_construct_stub(
7333 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007334 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007335 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007336}
7337
7338
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007339RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007340 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007341 ASSERT(args.length() == 1);
7342
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007343 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007345 // If the constructor isn't a proper function we throw a type error.
7346 if (!constructor->IsJSFunction()) {
7347 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7348 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007349 isolate->factory()->NewTypeError("not_constructor", arguments);
7350 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007351 }
7352
7353 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007354
7355 // If function should not have prototype, construction is not allowed. In this
7356 // case generated code bailouts here, since function has no initial_map.
7357 if (!function->should_have_prototype()) {
7358 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7359 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007360 isolate->factory()->NewTypeError("not_constructor", arguments);
7361 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007362 }
7363
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007364#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007365 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007366 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007367 if (debug->StepInActive()) {
7368 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007369 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007370#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007371
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007372 if (function->has_initial_map()) {
7373 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374 // The 'Function' function ignores the receiver object when
7375 // called using 'new' and creates a new JSFunction object that
7376 // is returned. The receiver object is only used for error
7377 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007378 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007379 // allocate JSFunctions since it does not properly initialize
7380 // the shared part of the function. Since the receiver is
7381 // ignored anyway, we use the global object as the receiver
7382 // instead of a new JSFunction object. This way, errors are
7383 // reported the same way whether or not 'Function' is called
7384 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007385 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007386 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387 }
7388
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007389 // The function should be compiled for the optimization hints to be
7390 // available. We cannot use EnsureCompiled because that forces a
7391 // compilation through the shared function info which makes it
7392 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007393 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007394 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007395
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007396 if (!function->has_initial_map() &&
7397 shared->IsInobjectSlackTrackingInProgress()) {
7398 // The tracking is already in progress for another function. We can only
7399 // track one initial_map at a time, so we force the completion before the
7400 // function is called as a constructor for the first time.
7401 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007402 }
7403
7404 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007405 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7406 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007407 // Delay setting the stub if inobject slack tracking is in progress.
7408 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007409 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007410 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007411
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007412 isolate->counters()->constructed_objects()->Increment();
7413 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007414
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007415 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007416}
7417
7418
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007419RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007420 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007421 ASSERT(args.length() == 1);
7422
7423 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7424 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007425 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007427 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007428}
7429
7430
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007431RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007432 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007433 ASSERT(args.length() == 1);
7434
7435 Handle<JSFunction> function = args.at<JSFunction>(0);
7436#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007437 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007438 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007439 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007440 PrintF("]\n");
7441 }
7442#endif
7443
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007444 // Compile the target function. Here we compile using CompileLazyInLoop in
7445 // order to get the optimized version. This helps code like delta-blue
7446 // that calls performance-critical routines through constructors. A
7447 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7448 // direct call. Since the in-loop tracking takes place through CallICs
7449 // this means that things called through constructors are never known to
7450 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007451 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007452 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007453 return Failure::Exception();
7454 }
7455
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007456 // All done. Return the compiled code.
7457 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007458 return function->code();
7459}
7460
7461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007462RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007463 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007464 ASSERT(args.length() == 1);
7465 Handle<JSFunction> function = args.at<JSFunction>(0);
7466 // If the function is not optimizable or debugger is active continue using the
7467 // code from the full compiler.
7468 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007469 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007470 if (FLAG_trace_opt) {
7471 PrintF("[failed to optimize ");
7472 function->PrintName();
7473 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7474 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007475 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007476 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007477 function->ReplaceCode(function->shared()->code());
7478 return function->code();
7479 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007480 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007481 return function->code();
7482 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007483 if (FLAG_trace_opt) {
7484 PrintF("[failed to optimize ");
7485 function->PrintName();
7486 PrintF(": optimized compilation failed]\n");
7487 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007488 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007489 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007490}
7491
7492
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007493RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007494 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007495 ASSERT(args.length() == 1);
7496 RUNTIME_ASSERT(args[0]->IsSmi());
7497 Deoptimizer::BailoutType type =
7498 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007499 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7500 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007501 int frames = deoptimizer->output_count();
7502
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007503 deoptimizer->MaterializeHeapNumbers();
7504 delete deoptimizer;
7505
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007506 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007507 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007508 for (int i = 0; i < frames - 1; i++) it.Advance();
7509 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007510
7511 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007512 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007513 Handle<Object> arguments;
7514 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007515 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007516 if (arguments.is_null()) {
7517 // FunctionGetArguments can't throw an exception, so cast away the
7518 // doubt with an assert.
7519 arguments = Handle<Object>(
7520 Accessors::FunctionGetArguments(*function,
7521 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007522 ASSERT(*arguments != isolate->heap()->null_value());
7523 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007524 }
7525 frame->SetExpression(i, *arguments);
7526 }
7527 }
7528
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007529 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007530 if (type == Deoptimizer::EAGER) {
7531 RUNTIME_ASSERT(function->IsOptimized());
7532 } else {
7533 RUNTIME_ASSERT(!function->IsOptimized());
7534 }
7535
7536 // Avoid doing too much work when running with --always-opt and keep
7537 // the optimized code around.
7538 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007539 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007540 }
7541
7542 // Count the number of optimized activations of the function.
7543 int activations = 0;
7544 while (!it.done()) {
7545 JavaScriptFrame* frame = it.frame();
7546 if (frame->is_optimized() && frame->function() == *function) {
7547 activations++;
7548 }
7549 it.Advance();
7550 }
7551
7552 // TODO(kasperl): For now, we cannot support removing the optimized
7553 // code when we have recursive invocations of the same function.
7554 if (activations == 0) {
7555 if (FLAG_trace_deopt) {
7556 PrintF("[removing optimized code for: ");
7557 function->PrintName();
7558 PrintF("]\n");
7559 }
7560 function->ReplaceCode(function->shared()->code());
7561 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007562 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007563}
7564
7565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007566RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007567 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007568 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007569 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007570}
7571
7572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007573RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007574 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007575 ASSERT(args.length() == 1);
7576 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007577 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007578
7579 Deoptimizer::DeoptimizeFunction(*function);
7580
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007581 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007582}
7583
7584
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007585RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7586 HandleScope scope(isolate);
7587 ASSERT(args.length() == 1);
7588 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7589 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7590 function->MarkForLazyRecompilation();
7591 return isolate->heap()->undefined_value();
7592}
7593
7594
lrn@chromium.org1c092762011-05-09 09:42:16 +00007595RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7596 HandleScope scope(isolate);
7597 ASSERT(args.length() == 1);
7598 if (!V8::UseCrankshaft()) {
7599 return Smi::FromInt(4); // 4 == "never".
7600 }
7601 if (FLAG_always_opt) {
7602 return Smi::FromInt(3); // 3 == "always".
7603 }
7604 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7605 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7606 : Smi::FromInt(2); // 2 == "no".
7607}
7608
7609
7610RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7611 HandleScope scope(isolate);
7612 ASSERT(args.length() == 1);
7613 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7614 return Smi::FromInt(function->shared()->opt_count());
7615}
7616
7617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007618RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007619 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007620 ASSERT(args.length() == 1);
7621 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7622
7623 // We're not prepared to handle a function with arguments object.
7624 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7625
7626 // We have hit a back edge in an unoptimized frame for a function that was
7627 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007628 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007629 // Keep track of whether we've succeeded in optimizing.
7630 bool succeeded = unoptimized->optimizable();
7631 if (succeeded) {
7632 // If we are trying to do OSR when there are already optimized
7633 // activations of the function, it means (a) the function is directly or
7634 // indirectly recursive and (b) an optimized invocation has been
7635 // deoptimized so that we are currently in an unoptimized activation.
7636 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007637 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007638 while (succeeded && !it.done()) {
7639 JavaScriptFrame* frame = it.frame();
7640 succeeded = !frame->is_optimized() || frame->function() != *function;
7641 it.Advance();
7642 }
7643 }
7644
7645 int ast_id = AstNode::kNoNumber;
7646 if (succeeded) {
7647 // The top JS function is this one, the PC is somewhere in the
7648 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007649 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007650 JavaScriptFrame* frame = it.frame();
7651 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007652 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007653 ASSERT(unoptimized->contains(frame->pc()));
7654
7655 // Use linear search of the unoptimized code's stack check table to find
7656 // the AST id matching the PC.
7657 Address start = unoptimized->instruction_start();
7658 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007659 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007660 uint32_t table_length = Memory::uint32_at(table_cursor);
7661 table_cursor += kIntSize;
7662 for (unsigned i = 0; i < table_length; ++i) {
7663 // Table entries are (AST id, pc offset) pairs.
7664 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7665 if (pc_offset == target_pc_offset) {
7666 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7667 break;
7668 }
7669 table_cursor += 2 * kIntSize;
7670 }
7671 ASSERT(ast_id != AstNode::kNoNumber);
7672 if (FLAG_trace_osr) {
7673 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7674 function->PrintName();
7675 PrintF("]\n");
7676 }
7677
7678 // Try to compile the optimized code. A true return value from
7679 // CompileOptimized means that compilation succeeded, not necessarily
7680 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007681 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7682 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007683 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7684 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007685 if (data->OsrPcOffset()->value() >= 0) {
7686 if (FLAG_trace_osr) {
7687 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007688 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007689 }
7690 ASSERT(data->OsrAstId()->value() == ast_id);
7691 } else {
7692 // We may never generate the desired OSR entry if we emit an
7693 // early deoptimize.
7694 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007695 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007696 } else {
7697 succeeded = false;
7698 }
7699 }
7700
7701 // Revert to the original stack checks in the original unoptimized code.
7702 if (FLAG_trace_osr) {
7703 PrintF("[restoring original stack checks in ");
7704 function->PrintName();
7705 PrintF("]\n");
7706 }
7707 StackCheckStub check_stub;
7708 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007709 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007710 Deoptimizer::RevertStackCheckCode(*unoptimized,
7711 *check_code,
7712 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007713
7714 // Allow OSR only at nesting level zero again.
7715 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7716
7717 // If the optimization attempt succeeded, return the AST id tagged as a
7718 // smi. This tells the builtin that we need to translate the unoptimized
7719 // frame to an optimized one.
7720 if (succeeded) {
7721 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7722 return Smi::FromInt(ast_id);
7723 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007724 if (function->IsMarkedForLazyRecompilation()) {
7725 function->ReplaceCode(function->shared()->code());
7726 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007727 return Smi::FromInt(-1);
7728 }
7729}
7730
7731
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007732RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007733 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007734 ASSERT(args.length() == 1);
7735 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7736 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7737}
7738
7739
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007740RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007741 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007742 ASSERT(args.length() == 1);
7743 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7744 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7745}
7746
7747
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007748RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007749 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007750 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007751
kasper.lund7276f142008-07-30 08:49:36 +00007752 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007753 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007754 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007755 { MaybeObject* maybe_result =
7756 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007757 if (!maybe_result->ToObject(&result)) return maybe_result;
7758 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007759
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007760 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007761
kasper.lund7276f142008-07-30 08:49:36 +00007762 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007763}
7764
lrn@chromium.org303ada72010-10-27 09:33:13 +00007765
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007766MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7767 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007768 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007769 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007770 Object* js_object = object;
7771 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007772 MaybeObject* maybe_js_object = js_object->ToObject();
7773 if (!maybe_js_object->ToObject(&js_object)) {
7774 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7775 return maybe_js_object;
7776 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007777 HandleScope scope(isolate);
7778 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007779 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007780 isolate->factory()->NewTypeError("with_expression",
7781 HandleVector(&handle, 1));
7782 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007783 }
7784 }
7785
lrn@chromium.org303ada72010-10-27 09:33:13 +00007786 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007787 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7788 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007789 if (!maybe_result->ToObject(&result)) return maybe_result;
7790 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007791
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007792 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007793 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007794
kasper.lund7276f142008-07-30 08:49:36 +00007795 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007796}
7797
7798
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007799RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007800 NoHandleAllocation ha;
7801 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007802 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007803}
7804
7805
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007806RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007807 NoHandleAllocation ha;
7808 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007809 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007810}
7811
7812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007813RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007814 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007815 ASSERT(args.length() == 2);
7816
7817 CONVERT_ARG_CHECKED(Context, context, 0);
7818 CONVERT_ARG_CHECKED(String, name, 1);
7819
7820 int index;
7821 PropertyAttributes attributes;
7822 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007823 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007824
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007825 // If the slot was not found the result is true.
7826 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007827 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007828 }
7829
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007830 // If the slot was found in a context, it should be DONT_DELETE.
7831 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007832 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007833 }
7834
7835 // The slot was found in a JSObject, either a context extension object,
7836 // the global object, or an arguments object. Try to delete it
7837 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7838 // which allows deleting all parameters in functions that mention
7839 // 'arguments', we do this even for the case of slots found on an
7840 // arguments object. The slot was found on an arguments object if the
7841 // index is non-negative.
7842 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7843 if (index >= 0) {
7844 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7845 } else {
7846 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7847 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007848}
7849
7850
ager@chromium.orga1645e22009-09-09 19:27:10 +00007851// A mechanism to return a pair of Object pointers in registers (if possible).
7852// How this is achieved is calling convention-dependent.
7853// All currently supported x86 compiles uses calling conventions that are cdecl
7854// variants where a 64-bit value is returned in two 32-bit registers
7855// (edx:eax on ia32, r1:r0 on ARM).
7856// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7857// In Win64 calling convention, a struct of two pointers is returned in memory,
7858// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007859#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007860struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007861 MaybeObject* x;
7862 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007863};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007864
lrn@chromium.org303ada72010-10-27 09:33:13 +00007865static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007866 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007867 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7868 // In Win64 they are assigned to a hidden first argument.
7869 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007870}
7871#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007872typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007873static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007874 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007875 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007876}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007877#endif
7878
7879
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007880static inline MaybeObject* Unhole(Heap* heap,
7881 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007882 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007883 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7884 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007885 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007886}
7887
7888
danno@chromium.org40cb8782011-05-25 07:58:50 +00007889static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
7890 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007891 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007892 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007893 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007894 JSFunction* context_extension_function =
7895 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007896 // If the holder isn't a context extension object, we just return it
7897 // as the receiver. This allows arguments objects to be used as
7898 // receivers, but only if they are put in the context scope chain
7899 // explicitly via a with-statement.
7900 Object* constructor = holder->map()->constructor();
7901 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00007902 // Fall back to using the global object as the implicit receiver if
7903 // the property turns out to be a local variable allocated in a
7904 // context extension object - introduced via eval. Implicit global
7905 // receivers are indicated with the hole value.
7906 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007907}
7908
7909
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007910static ObjectPair LoadContextSlotHelper(Arguments args,
7911 Isolate* isolate,
7912 bool throw_error) {
7913 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00007914 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007915
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007916 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007917 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007918 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007919 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007920 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007921
7922 int index;
7923 PropertyAttributes attributes;
7924 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007925 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007926
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007927 // If the index is non-negative, the slot has been found in a local
7928 // variable or a parameter. Read it from the context object or the
7929 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007930 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007931 // If the "property" we were looking for is a local variable or an
7932 // argument in a context, the receiver is the global object; see
7933 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00007934 //
7935 // Use the hole as the receiver to signal that the receiver is
7936 // implicit and that the global receiver should be used.
7937 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007938 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007939 ? Context::cast(*holder)->get(index)
7940 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007941 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007942 }
7943
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007944 // If the holder is found, we read the property from it.
7945 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007946 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007947 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00007948 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007949 if (object->IsGlobalObject()) {
7950 receiver = GlobalObject::cast(object)->global_receiver();
7951 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00007952 // Use the hole as the receiver to signal that the receiver is
7953 // implicit and that the global receiver should be used.
7954 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007955 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007956 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007957 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007958
7959 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00007960 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007961
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007962 // No need to unhole the value here. This is taken care of by the
7963 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007964 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007965 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007966 }
7967
7968 if (throw_error) {
7969 // The property doesn't exist - throw exception.
7970 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007971 isolate->factory()->NewReferenceError("not_defined",
7972 HandleVector(&name, 1));
7973 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007974 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00007975 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007976 return MakePair(isolate->heap()->undefined_value(),
7977 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007978 }
7979}
7980
7981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007982RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007983 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007984}
7985
7986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007987RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007988 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007989}
7990
7991
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007992RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007993 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007994 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007995
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007996 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007997 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007998 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007999 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
8000 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8001 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008002 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008003
8004 int index;
8005 PropertyAttributes attributes;
8006 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008007 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008008
8009 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008010 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008011 // Ignore if read_only variable.
8012 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008013 // Context is a fixed array and set cannot fail.
8014 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008015 } else if (strict_mode == kStrictMode) {
8016 // Setting read only property in strict mode.
8017 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008018 isolate->factory()->NewTypeError("strict_cannot_assign",
8019 HandleVector(&name, 1));
8020 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008021 }
8022 } else {
8023 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008024 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008025 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008026 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008027 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008028 return Failure::Exception();
8029 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008030 }
8031 return *value;
8032 }
8033
8034 // Slow case: The property is not in a FixedArray context.
8035 // It is either in an JSObject extension context or it was not found.
8036 Handle<JSObject> context_ext;
8037
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008038 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008039 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008040 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008041 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008042 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008043 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008044
8045 if (strict_mode == kStrictMode) {
8046 // Throw in strict mode (assignment to undefined variable).
8047 Handle<Object> error =
8048 isolate->factory()->NewReferenceError(
8049 "not_defined", HandleVector(&name, 1));
8050 return isolate->Throw(*error);
8051 }
8052 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008053 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008054 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008055 }
8056
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008057 // Set the property, but ignore if read_only variable on the context
8058 // extension object itself.
8059 if ((attributes & READ_ONLY) == 0 ||
8060 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008061 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008062 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008063 SetProperty(context_ext, name, value, NONE, strict_mode));
8064 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008065 // Setting read only property in strict mode.
8066 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008067 isolate->factory()->NewTypeError(
8068 "strict_cannot_assign", HandleVector(&name, 1));
8069 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008070 }
8071 return *value;
8072}
8073
8074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008075RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008076 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008077 ASSERT(args.length() == 1);
8078
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008079 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008080}
8081
8082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008083RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008084 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008085 ASSERT(args.length() == 1);
8086
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008087 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008088}
8089
8090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008091RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008092 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008093 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008094}
8095
8096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008097RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008098 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008099 ASSERT(args.length() == 1);
8100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008101 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008102 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008103 isolate->factory()->NewReferenceError("not_defined",
8104 HandleVector(&name, 1));
8105 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008106}
8107
8108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008109RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008110 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008111
8112 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008113 if (isolate->stack_guard()->IsStackOverflow()) {
8114 NoHandleAllocation na;
8115 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008116 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008117
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008118 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008119}
8120
8121
8122// NOTE: These PrintXXX functions are defined for all builds (not just
8123// DEBUG builds) because we may want to be able to trace function
8124// calls in all modes.
8125static void PrintString(String* str) {
8126 // not uncommon to have empty strings
8127 if (str->length() > 0) {
8128 SmartPointer<char> s =
8129 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8130 PrintF("%s", *s);
8131 }
8132}
8133
8134
8135static void PrintObject(Object* obj) {
8136 if (obj->IsSmi()) {
8137 PrintF("%d", Smi::cast(obj)->value());
8138 } else if (obj->IsString() || obj->IsSymbol()) {
8139 PrintString(String::cast(obj));
8140 } else if (obj->IsNumber()) {
8141 PrintF("%g", obj->Number());
8142 } else if (obj->IsFailure()) {
8143 PrintF("<failure>");
8144 } else if (obj->IsUndefined()) {
8145 PrintF("<undefined>");
8146 } else if (obj->IsNull()) {
8147 PrintF("<null>");
8148 } else if (obj->IsTrue()) {
8149 PrintF("<true>");
8150 } else if (obj->IsFalse()) {
8151 PrintF("<false>");
8152 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008153 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008154 }
8155}
8156
8157
8158static int StackSize() {
8159 int n = 0;
8160 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8161 return n;
8162}
8163
8164
8165static void PrintTransition(Object* result) {
8166 // indentation
8167 { const int nmax = 80;
8168 int n = StackSize();
8169 if (n <= nmax)
8170 PrintF("%4d:%*s", n, n, "");
8171 else
8172 PrintF("%4d:%*s", n, nmax, "...");
8173 }
8174
8175 if (result == NULL) {
8176 // constructor calls
8177 JavaScriptFrameIterator it;
8178 JavaScriptFrame* frame = it.frame();
8179 if (frame->IsConstructor()) PrintF("new ");
8180 // function name
8181 Object* fun = frame->function();
8182 if (fun->IsJSFunction()) {
8183 PrintObject(JSFunction::cast(fun)->shared()->name());
8184 } else {
8185 PrintObject(fun);
8186 }
8187 // function arguments
8188 // (we are intentionally only printing the actually
8189 // supplied parameters, not all parameters required)
8190 PrintF("(this=");
8191 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008192 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008193 for (int i = 0; i < length; i++) {
8194 PrintF(", ");
8195 PrintObject(frame->GetParameter(i));
8196 }
8197 PrintF(") {\n");
8198
8199 } else {
8200 // function result
8201 PrintF("} -> ");
8202 PrintObject(result);
8203 PrintF("\n");
8204 }
8205}
8206
8207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008208RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008209 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008210 NoHandleAllocation ha;
8211 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008212 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008213}
8214
8215
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008216RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008217 NoHandleAllocation ha;
8218 PrintTransition(args[0]);
8219 return args[0]; // return TOS
8220}
8221
8222
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008223RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008224 NoHandleAllocation ha;
8225 ASSERT(args.length() == 1);
8226
8227#ifdef DEBUG
8228 if (args[0]->IsString()) {
8229 // If we have a string, assume it's a code "marker"
8230 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008231 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008232 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008233 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8234 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008235 } else {
8236 PrintF("DebugPrint: ");
8237 }
8238 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008239 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008240 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008241 HeapObject::cast(args[0])->map()->Print();
8242 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008243#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008244 // ShortPrint is available in release mode. Print is not.
8245 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008246#endif
8247 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008248 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008249
8250 return args[0]; // return TOS
8251}
8252
8253
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008254RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008255 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008256 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008257 isolate->PrintStack();
8258 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008259}
8260
8261
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008262RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008263 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008264 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008265
8266 // According to ECMA-262, section 15.9.1, page 117, the precision of
8267 // the number in a Date object representing a particular instant in
8268 // time is milliseconds. Therefore, we floor the result of getting
8269 // the OS time.
8270 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008271 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008272}
8273
8274
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008275RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008276 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008277 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008278
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008279 CONVERT_ARG_CHECKED(String, str, 0);
8280 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008281
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008282 CONVERT_ARG_CHECKED(JSArray, output, 1);
8283 RUNTIME_ASSERT(output->HasFastElements());
8284
8285 AssertNoAllocation no_allocation;
8286
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008287 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008288 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8289 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008290 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008291 result = DateParser::Parse(str->ToAsciiVector(),
8292 output_array,
8293 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008294 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008295 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008296 result = DateParser::Parse(str->ToUC16Vector(),
8297 output_array,
8298 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008299 }
8300
8301 if (result) {
8302 return *output;
8303 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008304 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008305 }
8306}
8307
8308
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008309RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008310 NoHandleAllocation ha;
8311 ASSERT(args.length() == 1);
8312
8313 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008314 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008315 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008316}
8317
8318
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008319RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008320 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008321 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008323 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008324}
8325
8326
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008327RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008328 NoHandleAllocation ha;
8329 ASSERT(args.length() == 1);
8330
8331 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008332 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008333}
8334
8335
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008336RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008337 ASSERT(args.length() == 1);
8338 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008339 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008340 return JSGlobalObject::cast(global)->global_receiver();
8341}
8342
8343
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008344RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008345 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008346 ASSERT_EQ(1, args.length());
8347 CONVERT_ARG_CHECKED(String, source, 0);
8348
8349 Handle<Object> result = JsonParser::Parse(source);
8350 if (result.is_null()) {
8351 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008352 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008353 return Failure::Exception();
8354 }
8355 return *result;
8356}
8357
8358
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008359bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8360 Handle<Context> context) {
8361 if (context->allow_code_gen_from_strings()->IsFalse()) {
8362 // Check with callback if set.
8363 AllowCodeGenerationFromStringsCallback callback =
8364 isolate->allow_code_gen_callback();
8365 if (callback == NULL) {
8366 // No callback set and code generation disallowed.
8367 return false;
8368 } else {
8369 // Callback set. Let it decide if code generation is allowed.
8370 VMState state(isolate, EXTERNAL);
8371 return callback(v8::Utils::ToLocal(context));
8372 }
8373 }
8374 return true;
8375}
8376
8377
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008378RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008379 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008380 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008381 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008382
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008383 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008384 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008385
8386 // Check if global context allows code generation from
8387 // strings. Throw an exception if it doesn't.
8388 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8389 return isolate->Throw(*isolate->factory()->NewError(
8390 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8391 }
8392
8393 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008394 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8395 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008396 true,
8397 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008398 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008399 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008400 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8401 context,
8402 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008403 return *fun;
8404}
8405
8406
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008407static ObjectPair CompileGlobalEval(Isolate* isolate,
8408 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008409 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008410 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008411 Handle<Context> context = Handle<Context>(isolate->context());
8412 Handle<Context> global_context = Handle<Context>(context->global_context());
8413
8414 // Check if global context allows code generation from
8415 // strings. Throw an exception if it doesn't.
8416 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8417 isolate->Throw(*isolate->factory()->NewError(
8418 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8419 return MakePair(Failure::Exception(), NULL);
8420 }
8421
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008422 // Deal with a normal eval call with a string argument. Compile it
8423 // and return the compiled function bound in the local context.
8424 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8425 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008426 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008427 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008428 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008429 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008430 Handle<JSFunction> compiled =
8431 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008432 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008433 return MakePair(*compiled, *receiver);
8434}
8435
8436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008437RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008438 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008439
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008440 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008441 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008442 Handle<Object> receiver; // Will be overwritten.
8443
8444 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008445 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008446#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008447 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008448 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008449 StackFrameLocator locator;
8450 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008451 ASSERT(Context::cast(frame->context()) == *context);
8452#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008453
8454 // Find where the 'eval' symbol is bound. It is unaliased only if
8455 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008456 int index = -1;
8457 PropertyAttributes attributes = ABSENT;
8458 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008459 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8460 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008461 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008462 // Stop search when eval is found or when the global context is
8463 // reached.
8464 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008465 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008466 context = Handle<Context>(Context::cast(context->closure()->context()),
8467 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008468 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008469 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008470 }
8471 }
8472
iposva@chromium.org245aa852009-02-10 00:49:54 +00008473 // If eval could not be resolved, it has been deleted and we need to
8474 // throw a reference error.
8475 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008476 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008477 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008478 isolate->factory()->NewReferenceError("not_defined",
8479 HandleVector(&name, 1));
8480 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008481 }
8482
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008483 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008484 // 'eval' is not bound in the global context. Just call the function
8485 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008486 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008487 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008488 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008489 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008490 }
8491
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008492 // 'eval' is bound in the global context, but it may have been overwritten.
8493 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008494 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008495 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008496 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008497 }
8498
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008499 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008500 return CompileGlobalEval(isolate,
8501 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008502 args.at<Object>(2),
8503 static_cast<StrictModeFlag>(
8504 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008505}
8506
8507
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008508RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008509 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008510
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008511 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008512 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008513
8514 // 'eval' is bound in the global context, but it may have been overwritten.
8515 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008516 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008517 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008518 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008519 }
8520
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008521 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008522 return CompileGlobalEval(isolate,
8523 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008524 args.at<Object>(2),
8525 static_cast<StrictModeFlag>(
8526 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008527}
8528
8529
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008530RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008531 // This utility adjusts the property attributes for newly created Function
8532 // object ("new Function(...)") by changing the map.
8533 // All it does is changing the prototype property to enumerable
8534 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008535 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008536 ASSERT(args.length() == 1);
8537 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008538
8539 Handle<Map> map = func->shared()->strict_mode()
8540 ? isolate->strict_mode_function_instance_map()
8541 : isolate->function_instance_map();
8542
8543 ASSERT(func->map()->instance_type() == map->instance_type());
8544 ASSERT(func->map()->instance_size() == map->instance_size());
8545 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008546 return *func;
8547}
8548
8549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008550RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008551 // Allocate a block of memory in NewSpace (filled with a filler).
8552 // Use as fallback for allocation in generated code when NewSpace
8553 // is full.
8554 ASSERT(args.length() == 1);
8555 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8556 int size = size_smi->value();
8557 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8558 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008559 Heap* heap = isolate->heap();
8560 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008561 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008562 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008563 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008564 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008565 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008566 }
8567 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008568 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008569}
8570
8571
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008572// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008573// array. Returns true if the element was pushed on the stack and
8574// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008575RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008576 ASSERT(args.length() == 2);
8577 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008578 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008579 RUNTIME_ASSERT(array->HasFastElements());
8580 int length = Smi::cast(array->length())->value();
8581 FixedArray* elements = FixedArray::cast(array->elements());
8582 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008583 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008584 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008585 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008586 // Strict not needed. Used for cycle detection in Array join implementation.
8587 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8588 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008589 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8590 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008591 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008592}
8593
8594
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008595/**
8596 * A simple visitor visits every element of Array's.
8597 * The backend storage can be a fixed array for fast elements case,
8598 * or a dictionary for sparse array. Since Dictionary is a subtype
8599 * of FixedArray, the class can be used by both fast and slow cases.
8600 * The second parameter of the constructor, fast_elements, specifies
8601 * whether the storage is a FixedArray or Dictionary.
8602 *
8603 * An index limit is used to deal with the situation that a result array
8604 * length overflows 32-bit non-negative integer.
8605 */
8606class ArrayConcatVisitor {
8607 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008608 ArrayConcatVisitor(Isolate* isolate,
8609 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008610 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008611 isolate_(isolate),
8612 storage_(Handle<FixedArray>::cast(
8613 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008614 index_offset_(0u),
8615 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008616
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008617 ~ArrayConcatVisitor() {
8618 clear_storage();
8619 }
8620
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008621 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008622 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008623 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008624
8625 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008626 if (index < static_cast<uint32_t>(storage_->length())) {
8627 storage_->set(index, *elm);
8628 return;
8629 }
8630 // Our initial estimate of length was foiled, possibly by
8631 // getters on the arrays increasing the length of later arrays
8632 // during iteration.
8633 // This shouldn't happen in anything but pathological cases.
8634 SetDictionaryMode(index);
8635 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008636 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008637 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008638 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008639 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008640 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008641 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008642 // Dictionary needed to grow.
8643 clear_storage();
8644 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008645 }
8646}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008647
8648 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008649 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8650 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008651 } else {
8652 index_offset_ += delta;
8653 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008654 }
8655
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008656 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008657 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008658 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008659 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008660 Handle<Map> map;
8661 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008662 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008663 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008664 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008665 }
8666 array->set_map(*map);
8667 array->set_length(*length);
8668 array->set_elements(*storage_);
8669 return array;
8670 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008671
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008672 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008673 // Convert storage to dictionary mode.
8674 void SetDictionaryMode(uint32_t index) {
8675 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008676 Handle<FixedArray> current_storage(*storage_);
8677 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008678 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008679 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8680 for (uint32_t i = 0; i < current_length; i++) {
8681 HandleScope loop_scope;
8682 Handle<Object> element(current_storage->get(i));
8683 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008684 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008685 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008686 if (!new_storage.is_identical_to(slow_storage)) {
8687 slow_storage = loop_scope.CloseAndEscape(new_storage);
8688 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008689 }
8690 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008691 clear_storage();
8692 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008693 fast_elements_ = false;
8694 }
8695
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008696 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008697 isolate_->global_handles()->Destroy(
8698 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008699 }
8700
8701 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008702 storage_ = Handle<FixedArray>::cast(
8703 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008704 }
8705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008706 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008707 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008708 // Index after last seen index. Always less than or equal to
8709 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008710 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008711 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008712};
8713
8714
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008715static uint32_t EstimateElementCount(Handle<JSArray> array) {
8716 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8717 int element_count = 0;
8718 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008719 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008720 // Fast elements can't have lengths that are not representable by
8721 // a 32-bit signed integer.
8722 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8723 int fast_length = static_cast<int>(length);
8724 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8725 for (int i = 0; i < fast_length; i++) {
8726 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008727 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008728 break;
8729 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008730 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008731 Handle<NumberDictionary> dictionary(
8732 NumberDictionary::cast(array->elements()));
8733 int capacity = dictionary->Capacity();
8734 for (int i = 0; i < capacity; i++) {
8735 Handle<Object> key(dictionary->KeyAt(i));
8736 if (dictionary->IsKey(*key)) {
8737 element_count++;
8738 }
8739 }
8740 break;
8741 }
8742 default:
8743 // External arrays are always dense.
8744 return length;
8745 }
8746 // As an estimate, we assume that the prototype doesn't contain any
8747 // inherited elements.
8748 return element_count;
8749}
8750
8751
8752
8753template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008754static void IterateExternalArrayElements(Isolate* isolate,
8755 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008756 bool elements_are_ints,
8757 bool elements_are_guaranteed_smis,
8758 ArrayConcatVisitor* visitor) {
8759 Handle<ExternalArrayClass> array(
8760 ExternalArrayClass::cast(receiver->elements()));
8761 uint32_t len = static_cast<uint32_t>(array->length());
8762
8763 ASSERT(visitor != NULL);
8764 if (elements_are_ints) {
8765 if (elements_are_guaranteed_smis) {
8766 for (uint32_t j = 0; j < len; j++) {
8767 HandleScope loop_scope;
8768 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8769 visitor->visit(j, e);
8770 }
8771 } else {
8772 for (uint32_t j = 0; j < len; j++) {
8773 HandleScope loop_scope;
8774 int64_t val = static_cast<int64_t>(array->get(j));
8775 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8776 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8777 visitor->visit(j, e);
8778 } else {
8779 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008780 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008781 visitor->visit(j, e);
8782 }
8783 }
8784 }
8785 } else {
8786 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008787 HandleScope loop_scope(isolate);
8788 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008789 visitor->visit(j, e);
8790 }
8791 }
8792}
8793
8794
8795// Used for sorting indices in a List<uint32_t>.
8796static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8797 uint32_t a = *ap;
8798 uint32_t b = *bp;
8799 return (a == b) ? 0 : (a < b) ? -1 : 1;
8800}
8801
8802
8803static void CollectElementIndices(Handle<JSObject> object,
8804 uint32_t range,
8805 List<uint32_t>* indices) {
8806 JSObject::ElementsKind kind = object->GetElementsKind();
8807 switch (kind) {
8808 case JSObject::FAST_ELEMENTS: {
8809 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8810 uint32_t length = static_cast<uint32_t>(elements->length());
8811 if (range < length) length = range;
8812 for (uint32_t i = 0; i < length; i++) {
8813 if (!elements->get(i)->IsTheHole()) {
8814 indices->Add(i);
8815 }
8816 }
8817 break;
8818 }
8819 case JSObject::DICTIONARY_ELEMENTS: {
8820 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008821 uint32_t capacity = dict->Capacity();
8822 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008823 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008824 Handle<Object> k(dict->KeyAt(j));
8825 if (dict->IsKey(*k)) {
8826 ASSERT(k->IsNumber());
8827 uint32_t index = static_cast<uint32_t>(k->Number());
8828 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008829 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008830 }
8831 }
8832 }
8833 break;
8834 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008835 default: {
8836 int dense_elements_length;
8837 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008838 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008839 dense_elements_length =
8840 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008841 break;
8842 }
8843 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008844 dense_elements_length =
8845 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008846 break;
8847 }
8848 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008849 dense_elements_length =
8850 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008851 break;
8852 }
8853 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008854 dense_elements_length =
8855 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008856 break;
8857 }
8858 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008859 dense_elements_length =
8860 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008861 break;
8862 }
8863 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008864 dense_elements_length =
8865 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008866 break;
8867 }
8868 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008869 dense_elements_length =
8870 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008871 break;
8872 }
8873 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008874 dense_elements_length =
8875 ExternalFloatArray::cast(object->elements())->length();
8876 break;
8877 }
8878 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
8879 dense_elements_length =
8880 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008881 break;
8882 }
8883 default:
8884 UNREACHABLE();
8885 dense_elements_length = 0;
8886 break;
8887 }
8888 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8889 if (range <= length) {
8890 length = range;
8891 // We will add all indices, so we might as well clear it first
8892 // and avoid duplicates.
8893 indices->Clear();
8894 }
8895 for (uint32_t i = 0; i < length; i++) {
8896 indices->Add(i);
8897 }
8898 if (length == range) return; // All indices accounted for already.
8899 break;
8900 }
8901 }
8902
8903 Handle<Object> prototype(object->GetPrototype());
8904 if (prototype->IsJSObject()) {
8905 // The prototype will usually have no inherited element indices,
8906 // but we have to check.
8907 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8908 }
8909}
8910
8911
8912/**
8913 * A helper function that visits elements of a JSArray in numerical
8914 * order.
8915 *
8916 * The visitor argument called for each existing element in the array
8917 * with the element index and the element's value.
8918 * Afterwards it increments the base-index of the visitor by the array
8919 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008920 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008921 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008922static bool IterateElements(Isolate* isolate,
8923 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008924 ArrayConcatVisitor* visitor) {
8925 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8926 switch (receiver->GetElementsKind()) {
8927 case JSObject::FAST_ELEMENTS: {
8928 // Run through the elements FixedArray and use HasElement and GetElement
8929 // to check the prototype for missing elements.
8930 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8931 int fast_length = static_cast<int>(length);
8932 ASSERT(fast_length <= elements->length());
8933 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008934 HandleScope loop_scope(isolate);
8935 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008936 if (!element_value->IsTheHole()) {
8937 visitor->visit(j, element_value);
8938 } else if (receiver->HasElement(j)) {
8939 // Call GetElement on receiver, not its prototype, or getters won't
8940 // have the correct receiver.
8941 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008942 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008943 visitor->visit(j, element_value);
8944 }
8945 }
8946 break;
8947 }
8948 case JSObject::DICTIONARY_ELEMENTS: {
8949 Handle<NumberDictionary> dict(receiver->element_dictionary());
8950 List<uint32_t> indices(dict->Capacity() / 2);
8951 // Collect all indices in the object and the prototypes less
8952 // than length. This might introduce duplicates in the indices list.
8953 CollectElementIndices(receiver, length, &indices);
8954 indices.Sort(&compareUInt32);
8955 int j = 0;
8956 int n = indices.length();
8957 while (j < n) {
8958 HandleScope loop_scope;
8959 uint32_t index = indices[j];
8960 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008961 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008962 visitor->visit(index, element);
8963 // Skip to next different index (i.e., omit duplicates).
8964 do {
8965 j++;
8966 } while (j < n && indices[j] == index);
8967 }
8968 break;
8969 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008970 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8971 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8972 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008973 for (uint32_t j = 0; j < length; j++) {
8974 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8975 visitor->visit(j, e);
8976 }
8977 break;
8978 }
8979 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8980 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008981 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008982 break;
8983 }
8984 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8985 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008986 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008987 break;
8988 }
8989 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8990 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008991 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008992 break;
8993 }
8994 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8995 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008996 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008997 break;
8998 }
8999 case JSObject::EXTERNAL_INT_ELEMENTS: {
9000 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009001 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009002 break;
9003 }
9004 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9005 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009006 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009007 break;
9008 }
9009 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9010 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009011 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009012 break;
9013 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009014 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9015 IterateExternalArrayElements<ExternalDoubleArray, double>(
9016 isolate, receiver, false, false, visitor);
9017 break;
9018 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009019 default:
9020 UNREACHABLE();
9021 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009022 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009023 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009024 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009025}
9026
9027
9028/**
9029 * Array::concat implementation.
9030 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009031 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009032 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009033 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009034RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009035 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009036 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009037
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009038 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9039 int argument_count = static_cast<int>(arguments->length()->Number());
9040 RUNTIME_ASSERT(arguments->HasFastElements());
9041 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009042
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009043 // Pass 1: estimate the length and number of elements of the result.
9044 // The actual length can be larger if any of the arguments have getters
9045 // that mutate other arguments (but will otherwise be precise).
9046 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009047
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009048 uint32_t estimate_result_length = 0;
9049 uint32_t estimate_nof_elements = 0;
9050 {
9051 for (int i = 0; i < argument_count; i++) {
9052 HandleScope loop_scope;
9053 Handle<Object> obj(elements->get(i));
9054 uint32_t length_estimate;
9055 uint32_t element_estimate;
9056 if (obj->IsJSArray()) {
9057 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9058 length_estimate =
9059 static_cast<uint32_t>(array->length()->Number());
9060 element_estimate =
9061 EstimateElementCount(array);
9062 } else {
9063 length_estimate = 1;
9064 element_estimate = 1;
9065 }
9066 // Avoid overflows by capping at kMaxElementCount.
9067 if (JSObject::kMaxElementCount - estimate_result_length <
9068 length_estimate) {
9069 estimate_result_length = JSObject::kMaxElementCount;
9070 } else {
9071 estimate_result_length += length_estimate;
9072 }
9073 if (JSObject::kMaxElementCount - estimate_nof_elements <
9074 element_estimate) {
9075 estimate_nof_elements = JSObject::kMaxElementCount;
9076 } else {
9077 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009078 }
9079 }
9080 }
9081
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009082 // If estimated number of elements is more than half of length, a
9083 // fixed array (fast case) is more time and space-efficient than a
9084 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009085 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009086
9087 Handle<FixedArray> storage;
9088 if (fast_case) {
9089 // The backing storage array must have non-existing elements to
9090 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009091 storage = isolate->factory()->NewFixedArrayWithHoles(
9092 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009093 } else {
9094 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9095 uint32_t at_least_space_for = estimate_nof_elements +
9096 (estimate_nof_elements >> 2);
9097 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009098 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009099 }
9100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009101 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009102
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009103 for (int i = 0; i < argument_count; i++) {
9104 Handle<Object> obj(elements->get(i));
9105 if (obj->IsJSArray()) {
9106 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009107 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009108 return Failure::Exception();
9109 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009110 } else {
9111 visitor.visit(0, obj);
9112 visitor.increase_index_offset(1);
9113 }
9114 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009115
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009116 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009117}
9118
9119
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009120// This will not allocate (flatten the string), but it may run
9121// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009122RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009123 NoHandleAllocation ha;
9124 ASSERT(args.length() == 1);
9125
9126 CONVERT_CHECKED(String, string, args[0]);
9127 StringInputBuffer buffer(string);
9128 while (buffer.has_more()) {
9129 uint16_t character = buffer.GetNext();
9130 PrintF("%c", character);
9131 }
9132 return string;
9133}
9134
ager@chromium.org5ec48922009-05-05 07:25:34 +00009135// Moves all own elements of an object, that are below a limit, to positions
9136// starting at zero. All undefined values are placed after non-undefined values,
9137// and are followed by non-existing element. Does not change the length
9138// property.
9139// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009140RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009141 ASSERT(args.length() == 2);
9142 CONVERT_CHECKED(JSObject, object, args[0]);
9143 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9144 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009145}
9146
9147
9148// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009149RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009150 ASSERT(args.length() == 2);
9151 CONVERT_CHECKED(JSArray, from, args[0]);
9152 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009153 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009154 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009155 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9156 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009157 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009158 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009159 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009160 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009161 Object* new_map;
9162 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009163 to->set_map(Map::cast(new_map));
9164 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009165 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009166 Object* obj;
9167 { MaybeObject* maybe_obj = from->ResetElements();
9168 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9169 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009170 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009171 return to;
9172}
9173
9174
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009175// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009176RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009177 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009178 CONVERT_CHECKED(JSObject, object, args[0]);
9179 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009180 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009181 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009182 } else if (object->IsJSArray()) {
9183 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009184 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009185 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009186 }
9187}
9188
9189
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009190RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009191 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009192
9193 ASSERT_EQ(3, args.length());
9194
ager@chromium.orgac091b72010-05-05 07:34:42 +00009195 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009196 Handle<Object> key1 = args.at<Object>(1);
9197 Handle<Object> key2 = args.at<Object>(2);
9198
9199 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009200 if (!key1->ToArrayIndex(&index1)
9201 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009202 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009203 }
9204
ager@chromium.orgac091b72010-05-05 07:34:42 +00009205 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9206 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009207 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009208 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009209 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009210
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009211 RETURN_IF_EMPTY_HANDLE(isolate,
9212 SetElement(jsobject, index1, tmp2, kStrictMode));
9213 RETURN_IF_EMPTY_HANDLE(isolate,
9214 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009215
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009216 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009217}
9218
9219
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009220// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009221// might have elements. Can either return keys (positive integers) or
9222// intervals (pair of a negative integer (-start-1) followed by a
9223// positive (length)) or undefined values.
9224// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009225RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009226 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009227 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009228 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009229 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009230 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009231 // Create an array and get all the keys into it, then remove all the
9232 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009233 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009234 int keys_length = keys->length();
9235 for (int i = 0; i < keys_length; i++) {
9236 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009237 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009238 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009239 // Zap invalid keys.
9240 keys->set_undefined(i);
9241 }
9242 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009243 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009245 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009246 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009247 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009248 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009249 uint32_t actual_length =
9250 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009251 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009252 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009253 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009254 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009255 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009256 }
9257}
9258
9259
9260// DefineAccessor takes an optional final argument which is the
9261// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9262// to the way accessors are implemented, it is set for both the getter
9263// and setter on the first call to DefineAccessor and ignored on
9264// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009265RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009266 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9267 // Compute attributes.
9268 PropertyAttributes attributes = NONE;
9269 if (args.length() == 5) {
9270 CONVERT_CHECKED(Smi, attrs, args[4]);
9271 int value = attrs->value();
9272 // Only attribute bits should be set.
9273 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9274 attributes = static_cast<PropertyAttributes>(value);
9275 }
9276
9277 CONVERT_CHECKED(JSObject, obj, args[0]);
9278 CONVERT_CHECKED(String, name, args[1]);
9279 CONVERT_CHECKED(Smi, flag, args[2]);
9280 CONVERT_CHECKED(JSFunction, fun, args[3]);
9281 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9282}
9283
9284
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009285RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009286 ASSERT(args.length() == 3);
9287 CONVERT_CHECKED(JSObject, obj, args[0]);
9288 CONVERT_CHECKED(String, name, args[1]);
9289 CONVERT_CHECKED(Smi, flag, args[2]);
9290 return obj->LookupAccessor(name, flag->value() == 0);
9291}
9292
9293
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009294#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009295RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009296 ASSERT(args.length() == 0);
9297 return Execution::DebugBreakHelper();
9298}
9299
9300
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009301// Helper functions for wrapping and unwrapping stack frame ids.
9302static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009303 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009304 return Smi::FromInt(id >> 2);
9305}
9306
9307
9308static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9309 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9310}
9311
9312
9313// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009314// args[0]: debug event listener function to set or null or undefined for
9315// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009316// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009317RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009318 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009319 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9320 args[0]->IsUndefined() ||
9321 args[0]->IsNull());
9322 Handle<Object> callback = args.at<Object>(0);
9323 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009324 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009325
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009326 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009327}
9328
9329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009330RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009331 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009332 isolate->stack_guard()->DebugBreak();
9333 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009334}
9335
9336
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009337static MaybeObject* DebugLookupResultValue(Heap* heap,
9338 Object* receiver,
9339 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009340 LookupResult* result,
9341 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009342 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009343 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009344 case NORMAL:
9345 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009346 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009347 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009348 }
9349 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009350 case FIELD:
9351 value =
9352 JSObject::cast(
9353 result->holder())->FastPropertyAt(result->GetFieldIndex());
9354 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009355 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009356 }
9357 return value;
9358 case CONSTANT_FUNCTION:
9359 return result->GetConstantFunction();
9360 case CALLBACKS: {
9361 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009362 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009363 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009364 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009365 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009366 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009367 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009368 maybe_value = heap->isolate()->pending_exception();
9369 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009370 if (caught_exception != NULL) {
9371 *caught_exception = true;
9372 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009373 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009374 }
9375 return value;
9376 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009377 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009378 }
9379 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009380 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009381 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009382 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009383 case CONSTANT_TRANSITION:
9384 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009385 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009386 default:
9387 UNREACHABLE();
9388 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009389 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009390 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009391}
9392
9393
ager@chromium.org32912102009-01-16 10:38:43 +00009394// Get debugger related details for an object property.
9395// args[0]: object holding property
9396// args[1]: name of the property
9397//
9398// The array returned contains the following information:
9399// 0: Property value
9400// 1: Property details
9401// 2: Property value is exception
9402// 3: Getter function if defined
9403// 4: Setter function if defined
9404// Items 2-4 are only filled if the property has either a getter or a setter
9405// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009406RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009407 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009408
9409 ASSERT(args.length() == 2);
9410
9411 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9412 CONVERT_ARG_CHECKED(String, name, 1);
9413
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009414 // Make sure to set the current context to the context before the debugger was
9415 // entered (if the debugger is entered). The reason for switching context here
9416 // is that for some property lookups (accessors and interceptors) callbacks
9417 // into the embedding application can occour, and the embedding application
9418 // could have the assumption that its own global context is the current
9419 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009420 SaveContext save(isolate);
9421 if (isolate->debug()->InDebugger()) {
9422 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009423 }
9424
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009425 // Skip the global proxy as it has no properties and always delegates to the
9426 // real global object.
9427 if (obj->IsJSGlobalProxy()) {
9428 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9429 }
9430
9431
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009432 // Check if the name is trivially convertible to an index and get the element
9433 // if so.
9434 uint32_t index;
9435 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009436 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009437 Object* element_or_char;
9438 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009439 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009440 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9441 return maybe_element_or_char;
9442 }
9443 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009444 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009445 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009446 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009447 }
9448
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009449 // Find the number of objects making up this.
9450 int length = LocalPrototypeChainLength(*obj);
9451
9452 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009453 Handle<JSObject> jsproto = obj;
9454 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009455 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009456 jsproto->LocalLookup(*name, &result);
9457 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009458 // LookupResult is not GC safe as it holds raw object pointers.
9459 // GC can happen later in this code so put the required fields into
9460 // local variables using handles when required for later use.
9461 PropertyType result_type = result.type();
9462 Handle<Object> result_callback_obj;
9463 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009464 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9465 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009466 }
9467 Smi* property_details = result.GetPropertyDetails().AsSmi();
9468 // DebugLookupResultValue can cause GC so details from LookupResult needs
9469 // to be copied to handles before this.
9470 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009471 Object* raw_value;
9472 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009473 DebugLookupResultValue(isolate->heap(), *obj, *name,
9474 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009475 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9476 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009477 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009478
9479 // If the callback object is a fixed array then it contains JavaScript
9480 // getter and/or setter.
9481 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9482 result_callback_obj->IsFixedArray();
9483 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009484 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009485 details->set(0, *value);
9486 details->set(1, property_details);
9487 if (hasJavaScriptAccessors) {
9488 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009489 caught_exception ? isolate->heap()->true_value()
9490 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009491 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9492 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9493 }
9494
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009495 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009496 }
9497 if (i < length - 1) {
9498 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9499 }
9500 }
9501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009502 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009503}
9504
9505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009506RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009507 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009508
9509 ASSERT(args.length() == 2);
9510
9511 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9512 CONVERT_ARG_CHECKED(String, name, 1);
9513
9514 LookupResult result;
9515 obj->Lookup(*name, &result);
9516 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009517 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009518 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009519 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009520}
9521
9522
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009523// Return the property type calculated from the property details.
9524// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009525RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009526 ASSERT(args.length() == 1);
9527 CONVERT_CHECKED(Smi, details, args[0]);
9528 PropertyType type = PropertyDetails(details).type();
9529 return Smi::FromInt(static_cast<int>(type));
9530}
9531
9532
9533// Return the property attribute calculated from the property details.
9534// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009535RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009536 ASSERT(args.length() == 1);
9537 CONVERT_CHECKED(Smi, details, args[0]);
9538 PropertyAttributes attributes = PropertyDetails(details).attributes();
9539 return Smi::FromInt(static_cast<int>(attributes));
9540}
9541
9542
9543// Return the property insertion index calculated from the property details.
9544// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009545RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009546 ASSERT(args.length() == 1);
9547 CONVERT_CHECKED(Smi, details, args[0]);
9548 int index = PropertyDetails(details).index();
9549 return Smi::FromInt(index);
9550}
9551
9552
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009553// Return property value from named interceptor.
9554// args[0]: object
9555// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009556RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009557 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009558 ASSERT(args.length() == 2);
9559 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9560 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9561 CONVERT_ARG_CHECKED(String, name, 1);
9562
9563 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009564 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009565}
9566
9567
9568// Return element value from indexed interceptor.
9569// args[0]: object
9570// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009571RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009572 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009573 ASSERT(args.length() == 2);
9574 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9575 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9576 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9577
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009578 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009579}
9580
9581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009582RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009583 ASSERT(args.length() >= 1);
9584 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009585 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009586 if (isolate->debug()->break_id() == 0 ||
9587 break_id != isolate->debug()->break_id()) {
9588 return isolate->Throw(
9589 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009590 }
9591
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009592 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009593}
9594
9595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009596RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009597 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009598 ASSERT(args.length() == 1);
9599
9600 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009601 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009602 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9603 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009604 if (!maybe_result->ToObject(&result)) return maybe_result;
9605 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009606
9607 // Count all frames which are relevant to debugging stack trace.
9608 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009609 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009610 if (id == StackFrame::NO_ID) {
9611 // If there is no JavaScript stack frame count is 0.
9612 return Smi::FromInt(0);
9613 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009614 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009615 return Smi::FromInt(n);
9616}
9617
9618
9619static const int kFrameDetailsFrameIdIndex = 0;
9620static const int kFrameDetailsReceiverIndex = 1;
9621static const int kFrameDetailsFunctionIndex = 2;
9622static const int kFrameDetailsArgumentCountIndex = 3;
9623static const int kFrameDetailsLocalCountIndex = 4;
9624static const int kFrameDetailsSourcePositionIndex = 5;
9625static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009626static const int kFrameDetailsAtReturnIndex = 7;
9627static const int kFrameDetailsDebuggerFrameIndex = 8;
9628static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009629
9630// Return an array with frame details
9631// args[0]: number: break id
9632// args[1]: number: frame index
9633//
9634// The array returned contains the following information:
9635// 0: Frame id
9636// 1: Receiver
9637// 2: Function
9638// 3: Argument count
9639// 4: Local count
9640// 5: Source position
9641// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009642// 7: Is at return
9643// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009644// Arguments name, value
9645// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009646// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009647RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009648 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009649 ASSERT(args.length() == 2);
9650
9651 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009652 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009653 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9654 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009655 if (!maybe_check->ToObject(&check)) return maybe_check;
9656 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009657 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009658 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009659
9660 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009661 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009662 if (id == StackFrame::NO_ID) {
9663 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009664 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009665 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009666 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009667 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009668 for (; !it.done(); it.Advance()) {
9669 if (count == index) break;
9670 count++;
9671 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009672 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009673
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009674 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009675 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009676
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009677 // Traverse the saved contexts chain to find the active context for the
9678 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009679 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009680 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009681 save = save->prev();
9682 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009683 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009684
9685 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009686 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009687
9688 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009689 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009690 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009691
9692 // Check for constructor frame.
9693 bool constructor = it.frame()->IsConstructor();
9694
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009695 // Get scope info and read from it for local variable information.
9696 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009697 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009698 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009699
9700 // Get the context.
9701 Handle<Context> context(Context::cast(it.frame()->context()));
9702
9703 // Get the locals names and values into a temporary array.
9704 //
9705 // TODO(1240907): Hide compiler-introduced stack variables
9706 // (e.g. .result)? For users of the debugger, they will probably be
9707 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009708 Handle<FixedArray> locals =
9709 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009710
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009711 // Fill in the names of the locals.
9712 for (int i = 0; i < info.NumberOfLocals(); i++) {
9713 locals->set(i * 2, *info.LocalName(i));
9714 }
9715
9716 // Fill in the values of the locals.
9717 for (int i = 0; i < info.NumberOfLocals(); i++) {
9718 if (is_optimized_frame) {
9719 // If we are inspecting an optimized frame use undefined as the
9720 // value for all locals.
9721 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009722 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009723 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009724 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009725 } else if (i < info.number_of_stack_slots()) {
9726 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009727 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9728 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009729 // Traverse the context chain to the function context as all local
9730 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009731 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009732 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009733 context = Handle<Context>(context->previous());
9734 }
9735 ASSERT(context->is_function_context());
9736 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009737 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009738 }
9739 }
9740
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009741 // Check whether this frame is positioned at return. If not top
9742 // frame or if the frame is optimized it cannot be at a return.
9743 bool at_return = false;
9744 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009745 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009746 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009747
9748 // If positioned just before return find the value to be returned and add it
9749 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009750 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009751 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009752 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009753 Address internal_frame_sp = NULL;
9754 while (!it2.done()) {
9755 if (it2.frame()->is_internal()) {
9756 internal_frame_sp = it2.frame()->sp();
9757 } else {
9758 if (it2.frame()->is_java_script()) {
9759 if (it2.frame()->id() == it.frame()->id()) {
9760 // The internal frame just before the JavaScript frame contains the
9761 // value to return on top. A debug break at return will create an
9762 // internal frame to store the return value (eax/rax/r0) before
9763 // entering the debug break exit frame.
9764 if (internal_frame_sp != NULL) {
9765 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009766 Handle<Object>(Memory::Object_at(internal_frame_sp),
9767 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009768 break;
9769 }
9770 }
9771 }
9772
9773 // Indicate that the previous frame was not an internal frame.
9774 internal_frame_sp = NULL;
9775 }
9776 it2.Advance();
9777 }
9778 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009779
9780 // Now advance to the arguments adapter frame (if any). It contains all
9781 // the provided parameters whereas the function frame always have the number
9782 // of arguments matching the functions parameters. The rest of the
9783 // information (except for what is collected above) is the same.
9784 it.AdvanceToArgumentsFrame();
9785
9786 // Find the number of arguments to fill. At least fill the number of
9787 // parameters for the function and fill more if more parameters are provided.
9788 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009789 if (argument_count < it.frame()->ComputeParametersCount()) {
9790 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009791 }
9792
9793 // Calculate the size of the result.
9794 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009795 2 * (argument_count + info.NumberOfLocals()) +
9796 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009797 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009798
9799 // Add the frame id.
9800 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9801
9802 // Add the function (same as in function frame).
9803 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9804
9805 // Add the arguments count.
9806 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9807
9808 // Add the locals count
9809 details->set(kFrameDetailsLocalCountIndex,
9810 Smi::FromInt(info.NumberOfLocals()));
9811
9812 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009813 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009814 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9815 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009816 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009817 }
9818
9819 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009820 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009821
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009822 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009823 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009824
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009825 // Add information on whether this frame is invoked in the debugger context.
9826 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009827 heap->ToBoolean(*save->context() ==
9828 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009829
9830 // Fill the dynamic part.
9831 int details_index = kFrameDetailsFirstDynamicIndex;
9832
9833 // Add arguments name and value.
9834 for (int i = 0; i < argument_count; i++) {
9835 // Name of the argument.
9836 if (i < info.number_of_parameters()) {
9837 details->set(details_index++, *info.parameter_name(i));
9838 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009839 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009840 }
9841
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009842 // Parameter value. If we are inspecting an optimized frame, use
9843 // undefined as the value.
9844 //
9845 // TODO(3141533): We should be able to get the actual parameter
9846 // value for optimized frames.
9847 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009848 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009849 details->set(details_index++, it.frame()->GetParameter(i));
9850 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009851 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009852 }
9853 }
9854
9855 // Add locals name and value from the temporary copy from the function frame.
9856 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9857 details->set(details_index++, locals->get(i));
9858 }
9859
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009860 // Add the value being returned.
9861 if (at_return) {
9862 details->set(details_index++, *return_value);
9863 }
9864
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009865 // Add the receiver (same as in function frame).
9866 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9867 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009868 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009869 if (!receiver->IsJSObject()) {
9870 // If the receiver is NOT a JSObject we have hit an optimization
9871 // where a value object is not converted into a wrapped JS objects.
9872 // To hide this optimization from the debugger, we wrap the receiver
9873 // by creating correct wrapper object based on the calling frame's
9874 // global context.
9875 it.Advance();
9876 Handle<Context> calling_frames_global_context(
9877 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009878 receiver =
9879 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009880 }
9881 details->set(kFrameDetailsReceiverIndex, *receiver);
9882
9883 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009884 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009885}
9886
9887
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009888// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009889static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009890 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009891 Handle<SerializedScopeInfo> serialized_scope_info,
9892 ScopeInfo<>& scope_info,
9893 Handle<Context> context,
9894 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009895 // Fill all context locals to the context extension.
9896 for (int i = Context::MIN_CONTEXT_SLOTS;
9897 i < scope_info.number_of_context_slots();
9898 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009899 int context_index = serialized_scope_info->ContextSlotIndex(
9900 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009901
9902 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009903 if (*scope_info.context_slot_name(i) !=
9904 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009905 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009906 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009907 SetProperty(scope_object,
9908 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009909 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009910 NONE,
9911 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009912 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009913 }
9914 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009915
9916 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009917}
9918
9919
9920// Create a plain JSObject which materializes the local scope for the specified
9921// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009922static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
9923 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009924 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009925 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009926 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9927 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009928
9929 // Allocate and initialize a JSObject with all the arguments, stack locals
9930 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009931 Handle<JSObject> local_scope =
9932 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009933
9934 // First fill all parameters.
9935 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009936 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009937 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009938 SetProperty(local_scope,
9939 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009940 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009941 NONE,
9942 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009943 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009944 }
9945
9946 // Second fill all stack locals.
9947 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009948 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009949 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009950 SetProperty(local_scope,
9951 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009952 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009953 NONE,
9954 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009955 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009956 }
9957
9958 // Third fill all context locals.
9959 Handle<Context> frame_context(Context::cast(frame->context()));
9960 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009961 if (!CopyContextLocalsToScopeObject(isolate,
9962 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009963 function_context, local_scope)) {
9964 return Handle<JSObject>();
9965 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009966
9967 // Finally copy any properties from the function context extension. This will
9968 // be variables introduced by eval.
9969 if (function_context->closure() == *function) {
9970 if (function_context->has_extension() &&
9971 !function_context->IsGlobalContext()) {
9972 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009973 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009974 for (int i = 0; i < keys->length(); i++) {
9975 // Names of variables introduced by eval are strings.
9976 ASSERT(keys->get(i)->IsString());
9977 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009978 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009979 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009980 SetProperty(local_scope,
9981 key,
9982 GetProperty(ext, key),
9983 NONE,
9984 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009985 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009986 }
9987 }
9988 }
9989 return local_scope;
9990}
9991
9992
9993// Create a plain JSObject which materializes the closure content for the
9994// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009995static Handle<JSObject> MaterializeClosure(Isolate* isolate,
9996 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009997 ASSERT(context->is_function_context());
9998
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009999 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010000 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10001 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010002
10003 // Allocate and initialize a JSObject with all the content of theis function
10004 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010005 Handle<JSObject> closure_scope =
10006 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010007
10008 // Check whether the arguments shadow object exists.
10009 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010010 shared->scope_info()->ContextSlotIndex(
10011 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010012 if (arguments_shadow_index >= 0) {
10013 // In this case all the arguments are available in the arguments shadow
10014 // object.
10015 Handle<JSObject> arguments_shadow(
10016 JSObject::cast(context->get(arguments_shadow_index)));
10017 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010018 // We don't expect exception-throwing getters on the arguments shadow.
10019 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010020 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010021 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010022 SetProperty(closure_scope,
10023 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010024 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010025 NONE,
10026 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010027 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010028 }
10029 }
10030
10031 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010032 if (!CopyContextLocalsToScopeObject(isolate,
10033 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010034 context, closure_scope)) {
10035 return Handle<JSObject>();
10036 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010037
10038 // Finally copy any properties from the function context extension. This will
10039 // be variables introduced by eval.
10040 if (context->has_extension()) {
10041 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010042 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010043 for (int i = 0; i < keys->length(); i++) {
10044 // Names of variables introduced by eval are strings.
10045 ASSERT(keys->get(i)->IsString());
10046 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010047 RETURN_IF_EMPTY_HANDLE_VALUE(
10048 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010049 SetProperty(closure_scope,
10050 key,
10051 GetProperty(ext, key),
10052 NONE,
10053 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010054 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010055 }
10056 }
10057
10058 return closure_scope;
10059}
10060
10061
10062// Iterate over the actual scopes visible from a stack frame. All scopes are
10063// backed by an actual context except the local scope, which is inserted
10064// "artifically" in the context chain.
10065class ScopeIterator {
10066 public:
10067 enum ScopeType {
10068 ScopeTypeGlobal = 0,
10069 ScopeTypeLocal,
10070 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010071 ScopeTypeClosure,
10072 // Every catch block contains an implicit with block (its parameter is
10073 // a JSContextExtensionObject) that extends current scope with a variable
10074 // holding exception object. Such with blocks are treated as scopes of their
10075 // own type.
10076 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010077 };
10078
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010079 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10080 : isolate_(isolate),
10081 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010082 function_(JSFunction::cast(frame->function())),
10083 context_(Context::cast(frame->context())),
10084 local_done_(false),
10085 at_local_(false) {
10086
10087 // Check whether the first scope is actually a local scope.
10088 if (context_->IsGlobalContext()) {
10089 // If there is a stack slot for .result then this local scope has been
10090 // created for evaluating top level code and it is not a real local scope.
10091 // Checking for the existence of .result seems fragile, but the scope info
10092 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010093 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010094 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010095 at_local_ = index < 0;
10096 } else if (context_->is_function_context()) {
10097 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010098 } else if (context_->closure() != *function_) {
10099 // The context_ is a with block from the outer function.
10100 ASSERT(context_->has_extension());
10101 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010102 }
10103 }
10104
10105 // More scopes?
10106 bool Done() { return context_.is_null(); }
10107
10108 // Move to the next scope.
10109 void Next() {
10110 // If at a local scope mark the local scope as passed.
10111 if (at_local_) {
10112 at_local_ = false;
10113 local_done_ = true;
10114
10115 // If the current context is not associated with the local scope the
10116 // current context is the next real scope, so don't move to the next
10117 // context in this case.
10118 if (context_->closure() != *function_) {
10119 return;
10120 }
10121 }
10122
10123 // The global scope is always the last in the chain.
10124 if (context_->IsGlobalContext()) {
10125 context_ = Handle<Context>();
10126 return;
10127 }
10128
10129 // Move to the next context.
10130 if (context_->is_function_context()) {
10131 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
10132 } else {
10133 context_ = Handle<Context>(context_->previous());
10134 }
10135
10136 // If passing the local scope indicate that the current scope is now the
10137 // local scope.
10138 if (!local_done_ &&
10139 (context_->IsGlobalContext() || (context_->is_function_context()))) {
10140 at_local_ = true;
10141 }
10142 }
10143
10144 // Return the type of the current scope.
10145 int Type() {
10146 if (at_local_) {
10147 return ScopeTypeLocal;
10148 }
10149 if (context_->IsGlobalContext()) {
10150 ASSERT(context_->global()->IsGlobalObject());
10151 return ScopeTypeGlobal;
10152 }
10153 if (context_->is_function_context()) {
10154 return ScopeTypeClosure;
10155 }
10156 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +000010157 // Current scope is either an explicit with statement or a with statement
10158 // implicitely generated for a catch block.
10159 // If the extension object here is a JSContextExtensionObject then
10160 // current with statement is one frome a catch block otherwise it's a
10161 // regular with statement.
10162 if (context_->extension()->IsJSContextExtensionObject()) {
10163 return ScopeTypeCatch;
10164 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010165 return ScopeTypeWith;
10166 }
10167
10168 // Return the JavaScript object with the content of the current scope.
10169 Handle<JSObject> ScopeObject() {
10170 switch (Type()) {
10171 case ScopeIterator::ScopeTypeGlobal:
10172 return Handle<JSObject>(CurrentContext()->global());
10173 break;
10174 case ScopeIterator::ScopeTypeLocal:
10175 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010176 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010177 break;
10178 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010179 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010180 // Return the with object.
10181 return Handle<JSObject>(CurrentContext()->extension());
10182 break;
10183 case ScopeIterator::ScopeTypeClosure:
10184 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010185 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010186 break;
10187 }
10188 UNREACHABLE();
10189 return Handle<JSObject>();
10190 }
10191
10192 // Return the context for this scope. For the local context there might not
10193 // be an actual context.
10194 Handle<Context> CurrentContext() {
10195 if (at_local_ && context_->closure() != *function_) {
10196 return Handle<Context>();
10197 }
10198 return context_;
10199 }
10200
10201#ifdef DEBUG
10202 // Debug print of the content of the current scope.
10203 void DebugPrint() {
10204 switch (Type()) {
10205 case ScopeIterator::ScopeTypeGlobal:
10206 PrintF("Global:\n");
10207 CurrentContext()->Print();
10208 break;
10209
10210 case ScopeIterator::ScopeTypeLocal: {
10211 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010212 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010213 scope_info.Print();
10214 if (!CurrentContext().is_null()) {
10215 CurrentContext()->Print();
10216 if (CurrentContext()->has_extension()) {
10217 Handle<JSObject> extension =
10218 Handle<JSObject>(CurrentContext()->extension());
10219 if (extension->IsJSContextExtensionObject()) {
10220 extension->Print();
10221 }
10222 }
10223 }
10224 break;
10225 }
10226
10227 case ScopeIterator::ScopeTypeWith: {
10228 PrintF("With:\n");
10229 Handle<JSObject> extension =
10230 Handle<JSObject>(CurrentContext()->extension());
10231 extension->Print();
10232 break;
10233 }
10234
ager@chromium.orga1645e22009-09-09 19:27:10 +000010235 case ScopeIterator::ScopeTypeCatch: {
10236 PrintF("Catch:\n");
10237 Handle<JSObject> extension =
10238 Handle<JSObject>(CurrentContext()->extension());
10239 extension->Print();
10240 break;
10241 }
10242
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010243 case ScopeIterator::ScopeTypeClosure: {
10244 PrintF("Closure:\n");
10245 CurrentContext()->Print();
10246 if (CurrentContext()->has_extension()) {
10247 Handle<JSObject> extension =
10248 Handle<JSObject>(CurrentContext()->extension());
10249 if (extension->IsJSContextExtensionObject()) {
10250 extension->Print();
10251 }
10252 }
10253 break;
10254 }
10255
10256 default:
10257 UNREACHABLE();
10258 }
10259 PrintF("\n");
10260 }
10261#endif
10262
10263 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010264 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010265 JavaScriptFrame* frame_;
10266 Handle<JSFunction> function_;
10267 Handle<Context> context_;
10268 bool local_done_;
10269 bool at_local_;
10270
10271 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10272};
10273
10274
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010275RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010276 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010277 ASSERT(args.length() == 2);
10278
10279 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010280 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010281 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10282 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010283 if (!maybe_check->ToObject(&check)) return maybe_check;
10284 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010285 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10286
10287 // Get the frame where the debugging is performed.
10288 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010289 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010290 JavaScriptFrame* frame = it.frame();
10291
10292 // Count the visible scopes.
10293 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010294 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010295 n++;
10296 }
10297
10298 return Smi::FromInt(n);
10299}
10300
10301
10302static const int kScopeDetailsTypeIndex = 0;
10303static const int kScopeDetailsObjectIndex = 1;
10304static const int kScopeDetailsSize = 2;
10305
10306// Return an array with scope details
10307// args[0]: number: break id
10308// args[1]: number: frame index
10309// args[2]: number: scope index
10310//
10311// The array returned contains the following information:
10312// 0: Scope type
10313// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010314RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010315 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010316 ASSERT(args.length() == 3);
10317
10318 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010319 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010320 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10321 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010322 if (!maybe_check->ToObject(&check)) return maybe_check;
10323 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010324 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10325 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10326
10327 // Get the frame where the debugging is performed.
10328 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010329 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010330 JavaScriptFrame* frame = frame_it.frame();
10331
10332 // Find the requested scope.
10333 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010334 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010335 for (; !it.Done() && n < index; it.Next()) {
10336 n++;
10337 }
10338 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010339 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010340 }
10341
10342 // Calculate the size of the result.
10343 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010344 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010345
10346 // Fill in scope details.
10347 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010348 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010349 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010350 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010351
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010352 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010353}
10354
10355
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010356RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010357 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010358 ASSERT(args.length() == 0);
10359
10360#ifdef DEBUG
10361 // Print the scopes for the top frame.
10362 StackFrameLocator locator;
10363 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010364 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010365 it.DebugPrint();
10366 }
10367#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010368 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010369}
10370
10371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010372RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010373 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010374 ASSERT(args.length() == 1);
10375
10376 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010377 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010378 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10379 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010380 if (!maybe_result->ToObject(&result)) return maybe_result;
10381 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010382
10383 // Count all archived V8 threads.
10384 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010385 for (ThreadState* thread =
10386 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010387 thread != NULL;
10388 thread = thread->Next()) {
10389 n++;
10390 }
10391
10392 // Total number of threads is current thread and archived threads.
10393 return Smi::FromInt(n + 1);
10394}
10395
10396
10397static const int kThreadDetailsCurrentThreadIndex = 0;
10398static const int kThreadDetailsThreadIdIndex = 1;
10399static const int kThreadDetailsSize = 2;
10400
10401// Return an array with thread details
10402// args[0]: number: break id
10403// args[1]: number: thread index
10404//
10405// The array returned contains the following information:
10406// 0: Is current thread?
10407// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010408RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010409 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010410 ASSERT(args.length() == 2);
10411
10412 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010413 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010414 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10415 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010416 if (!maybe_check->ToObject(&check)) return maybe_check;
10417 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010418 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10419
10420 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010421 Handle<FixedArray> details =
10422 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010423
10424 // Thread index 0 is current thread.
10425 if (index == 0) {
10426 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010427 details->set(kThreadDetailsCurrentThreadIndex,
10428 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010429 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010430 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010431 } else {
10432 // Find the thread with the requested index.
10433 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010434 ThreadState* thread =
10435 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010436 while (index != n && thread != NULL) {
10437 thread = thread->Next();
10438 n++;
10439 }
10440 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010441 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010442 }
10443
10444 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010445 details->set(kThreadDetailsCurrentThreadIndex,
10446 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010447 details->set(kThreadDetailsThreadIdIndex,
10448 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010449 }
10450
10451 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010452 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010453}
10454
10455
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010456// Sets the disable break state
10457// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010458RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010459 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010460 ASSERT(args.length() == 1);
10461 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010462 isolate->debug()->set_disable_break(disable_break);
10463 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010464}
10465
10466
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010467RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010468 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010469 ASSERT(args.length() == 1);
10470
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010471 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10472 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010473 // Find the number of break points
10474 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010475 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010476 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010477 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010478 Handle<FixedArray>::cast(break_locations));
10479}
10480
10481
10482// Set a break point in a function
10483// args[0]: function
10484// args[1]: number: break source position (within the function source)
10485// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010486RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010487 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010488 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010489 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10490 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010491 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10492 RUNTIME_ASSERT(source_position >= 0);
10493 Handle<Object> break_point_object_arg = args.at<Object>(2);
10494
10495 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010496 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10497 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010498
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010499 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010500}
10501
10502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010503Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10504 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010505 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010506 // Iterate the heap looking for SharedFunctionInfo generated from the
10507 // script. The inner most SharedFunctionInfo containing the source position
10508 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010509 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010510 // which is found is not compiled it is compiled and the heap is iterated
10511 // again as the compilation might create inner functions from the newly
10512 // compiled function and the actual requested break point might be in one of
10513 // these functions.
10514 bool done = false;
10515 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010516 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010517 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010518 while (!done) {
10519 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010520 for (HeapObject* obj = iterator.next();
10521 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010522 if (obj->IsSharedFunctionInfo()) {
10523 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10524 if (shared->script() == *script) {
10525 // If the SharedFunctionInfo found has the requested script data and
10526 // contains the source position it is a candidate.
10527 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010528 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010529 start_position = shared->start_position();
10530 }
10531 if (start_position <= position &&
10532 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010533 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534 // candidate this is the new candidate.
10535 if (target.is_null()) {
10536 target_start_position = start_position;
10537 target = shared;
10538 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010539 if (target_start_position == start_position &&
10540 shared->end_position() == target->end_position()) {
10541 // If a top-level function contain only one function
10542 // declartion the source for the top-level and the function is
10543 // the same. In that case prefer the non top-level function.
10544 if (!shared->is_toplevel()) {
10545 target_start_position = start_position;
10546 target = shared;
10547 }
10548 } else if (target_start_position <= start_position &&
10549 shared->end_position() <= target->end_position()) {
10550 // This containment check includes equality as a function inside
10551 // a top-level function can share either start or end position
10552 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010553 target_start_position = start_position;
10554 target = shared;
10555 }
10556 }
10557 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010558 }
10559 }
10560 }
10561
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010562 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010563 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010564 }
10565
10566 // If the candidate found is compiled we are done. NOTE: when lazy
10567 // compilation of inner functions is introduced some additional checking
10568 // needs to be done here to compile inner functions.
10569 done = target->is_compiled();
10570 if (!done) {
10571 // If the candidate is not compiled compile it to reveal any inner
10572 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010573 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574 }
10575 }
10576
10577 return *target;
10578}
10579
10580
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010581// Changes the state of a break point in a script and returns source position
10582// where break point was set. NOTE: Regarding performance see the NOTE for
10583// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584// args[0]: script to set break point in
10585// args[1]: number: break source position (within the script source)
10586// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010587RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010588 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010589 ASSERT(args.length() == 3);
10590 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10591 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10592 RUNTIME_ASSERT(source_position >= 0);
10593 Handle<Object> break_point_object_arg = args.at<Object>(2);
10594
10595 // Get the script from the script wrapper.
10596 RUNTIME_ASSERT(wrapper->value()->IsScript());
10597 Handle<Script> script(Script::cast(wrapper->value()));
10598
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010599 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010600 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010601 if (!result->IsUndefined()) {
10602 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10603 // Find position within function. The script position might be before the
10604 // source position of the first function.
10605 int position;
10606 if (shared->start_position() > source_position) {
10607 position = 0;
10608 } else {
10609 position = source_position - shared->start_position();
10610 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010611 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010612 position += shared->start_position();
10613 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010614 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010615 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010616}
10617
10618
10619// Clear a break point
10620// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010621RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010622 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623 ASSERT(args.length() == 1);
10624 Handle<Object> break_point_object_arg = args.at<Object>(0);
10625
10626 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010627 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010628
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010629 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010630}
10631
10632
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010633// Change the state of break on exceptions.
10634// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10635// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010636RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010637 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010638 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010639 RUNTIME_ASSERT(args[0]->IsNumber());
10640 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010641
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010642 // If the number doesn't match an enum value, the ChangeBreakOnException
10643 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010644 ExceptionBreakType type =
10645 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010646 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010647 isolate->debug()->ChangeBreakOnException(type, enable);
10648 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010649}
10650
10651
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010652// Returns the state of break on exceptions
10653// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010654RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010655 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010656 ASSERT(args.length() == 1);
10657 RUNTIME_ASSERT(args[0]->IsNumber());
10658
10659 ExceptionBreakType type =
10660 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010661 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010662 return Smi::FromInt(result);
10663}
10664
10665
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010666// Prepare for stepping
10667// args[0]: break id for checking execution state
10668// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010669// args[2]: number of times to perform the step, for step out it is the number
10670// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010671RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010672 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010673 ASSERT(args.length() == 3);
10674 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010675 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010676 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10677 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010678 if (!maybe_check->ToObject(&check)) return maybe_check;
10679 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010680 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010681 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010682 }
10683
10684 // Get the step action and check validity.
10685 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10686 if (step_action != StepIn &&
10687 step_action != StepNext &&
10688 step_action != StepOut &&
10689 step_action != StepInMin &&
10690 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010691 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010692 }
10693
10694 // Get the number of steps.
10695 int step_count = NumberToInt32(args[2]);
10696 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010697 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010698 }
10699
ager@chromium.orga1645e22009-09-09 19:27:10 +000010700 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010701 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010702
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010703 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010704 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10705 step_count);
10706 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010707}
10708
10709
10710// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010711RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010712 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010713 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010714 isolate->debug()->ClearStepping();
10715 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010716}
10717
10718
10719// Creates a copy of the with context chain. The copy of the context chain is
10720// is linked to the function context supplied.
10721static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10722 Handle<Context> function_context) {
10723 // At the bottom of the chain. Return the function context to link to.
10724 if (context_chain->is_function_context()) {
10725 return function_context;
10726 }
10727
10728 // Recursively copy the with contexts.
10729 Handle<Context> previous(context_chain->previous());
10730 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
danno@chromium.org160a7b02011-04-18 15:51:38 +000010731 Handle<Context> context = CopyWithContextChain(previous, function_context);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010732 return context->GetIsolate()->factory()->NewWithContext(
10733 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010734}
10735
10736
10737// Helper function to find or create the arguments object for
10738// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010739static Handle<Object> GetArgumentsObject(Isolate* isolate,
10740 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010741 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010742 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010743 const ScopeInfo<>* sinfo,
10744 Handle<Context> function_context) {
10745 // Try to find the value of 'arguments' to pass as parameter. If it is not
10746 // found (that is the debugged function does not reference 'arguments' and
10747 // does not support eval) then create an 'arguments' object.
10748 int index;
10749 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010750 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010751 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010752 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010753 }
10754 }
10755
10756 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010757 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10758 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010759 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010760 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010761 }
10762 }
10763
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010764 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010765 Handle<JSObject> arguments =
10766 isolate->factory()->NewArgumentsObject(function, length);
10767 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010768
10769 AssertNoAllocation no_gc;
10770 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010771 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010772 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010773 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010774 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010775 return arguments;
10776}
10777
10778
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010779static const char kSourceStr[] =
10780 "(function(arguments,__source__){return eval(__source__);})";
10781
10782
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010783// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010784// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010785// extension part has all the parameters and locals of the function on the
10786// stack frame. A function which calls eval with the code to evaluate is then
10787// compiled in this context and called in this context. As this context
10788// replaces the context of the function on the stack frame a new (empty)
10789// function is created as well to be used as the closure for the context.
10790// This function and the context acts as replacements for the function on the
10791// stack frame presenting the same view of the values of parameters and
10792// local variables as if the piece of JavaScript was evaluated at the point
10793// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010794RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010795 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010796
10797 // Check the execution state and decode arguments frame and source to be
10798 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010799 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010800 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010801 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10802 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010803 if (!maybe_check_result->ToObject(&check_result)) {
10804 return maybe_check_result;
10805 }
10806 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010807 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10808 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010809 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010810 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010811
10812 // Handle the processing of break.
10813 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010814
10815 // Get the frame where the debugging is performed.
10816 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010817 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010818 JavaScriptFrame* frame = it.frame();
10819 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010820 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010821 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010822
10823 // Traverse the saved contexts chain to find the active context for the
10824 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010825 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010826 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010827 save = save->prev();
10828 }
10829 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010830 SaveContext savex(isolate);
10831 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010832
10833 // Create the (empty) function replacing the function on the stack frame for
10834 // the purpose of evaluating in the context created below. It is important
10835 // that this function does not describe any parameters and local variables
10836 // in the context. If it does then this will cause problems with the lookup
10837 // in Context::Lookup, where context slots for parameters and local variables
10838 // are looked at before the extension object.
10839 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010840 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10841 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010842 go_between->set_context(function->context());
10843#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010844 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010845 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10846 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10847#endif
10848
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010849 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010850 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10851 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010852
10853 // Allocate a new context for the debug evaluation and set the extension
10854 // object build.
10855 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010856 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10857 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010858 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010859 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010860 Handle<Context> frame_context(Context::cast(frame->context()));
10861 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010862 context = CopyWithContextChain(frame_context, context);
10863
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010864 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010865 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010866 Handle<JSObject>::cast(additional_context), false);
10867 }
10868
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010869 // Wrap the evaluation statement in a new function compiled in the newly
10870 // created context. The function has one parameter which has to be called
10871 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010872 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010874
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010875 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010876 isolate->factory()->NewStringFromAscii(
10877 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010878
10879 // Currently, the eval code will be executed in non-strict mode,
10880 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010881 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010882 Compiler::CompileEval(function_source,
10883 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010884 context->IsGlobalContext(),
10885 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010886 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010887 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010888 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010889
10890 // Invoke the result of the compilation to get the evaluation function.
10891 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010892 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010893 Handle<Object> evaluation_function =
10894 Execution::Call(compiled_function, receiver, 0, NULL,
10895 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010896 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010897
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010898 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
10899 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010900 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010901
10902 // Invoke the evaluation function and return the result.
10903 const int argc = 2;
10904 Object** argv[argc] = { arguments.location(),
10905 Handle<Object>::cast(source).location() };
10906 Handle<Object> result =
10907 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10908 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010909 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010910
10911 // Skip the global proxy as it has no properties and always delegates to the
10912 // real global object.
10913 if (result->IsJSGlobalProxy()) {
10914 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10915 }
10916
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010917 return *result;
10918}
10919
10920
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010921RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010922 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010923
10924 // Check the execution state and decode arguments frame and source to be
10925 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010926 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010927 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010928 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10929 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010930 if (!maybe_check_result->ToObject(&check_result)) {
10931 return maybe_check_result;
10932 }
10933 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010934 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010935 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010936 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010937
10938 // Handle the processing of break.
10939 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010940
10941 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010942 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010943 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010944 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010945 top = top->prev();
10946 }
10947 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010948 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010949 }
10950
10951 // Get the global context now set to the top context from before the
10952 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010953 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010954
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010955 bool is_global = true;
10956
10957 if (additional_context->IsJSObject()) {
10958 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010959 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10960 isolate->factory()->empty_string(),
10961 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010962 go_between->set_context(*context);
10963 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010964 isolate->factory()->NewFunctionContext(
10965 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010966 context->set_extension(JSObject::cast(*additional_context));
10967 is_global = false;
10968 }
10969
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010970 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010971 // Currently, the eval code will be executed in non-strict mode,
10972 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010973 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010974 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010975 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010976 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010977 Handle<JSFunction>(
10978 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10979 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010980
10981 // Invoke the result of the compilation to get the evaluation function.
10982 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010983 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010984 Handle<Object> result =
10985 Execution::Call(compiled_function, receiver, 0, NULL,
10986 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010987 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010988 return *result;
10989}
10990
10991
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010992RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010993 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010994 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010995
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010996 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010997 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010998
10999 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011000 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011001 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11002 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11003 // because using
11004 // instances->set(i, *GetScriptWrapper(script))
11005 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11006 // already have deferenced the instances handle.
11007 Handle<JSValue> wrapper = GetScriptWrapper(script);
11008 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011009 }
11010
11011 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011012 Handle<JSObject> result =
11013 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011014 Handle<JSArray>::cast(result)->SetContent(*instances);
11015 return *result;
11016}
11017
11018
11019// Helper function used by Runtime_DebugReferencedBy below.
11020static int DebugReferencedBy(JSObject* target,
11021 Object* instance_filter, int max_references,
11022 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011023 JSFunction* arguments_function) {
11024 NoHandleAllocation ha;
11025 AssertNoAllocation no_alloc;
11026
11027 // Iterate the heap.
11028 int count = 0;
11029 JSObject* last = NULL;
11030 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011031 HeapObject* heap_obj = NULL;
11032 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011033 (max_references == 0 || count < max_references)) {
11034 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011035 if (heap_obj->IsJSObject()) {
11036 // Skip context extension objects and argument arrays as these are
11037 // checked in the context of functions using them.
11038 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011039 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011040 obj->map()->constructor() == arguments_function) {
11041 continue;
11042 }
11043
11044 // Check if the JS object has a reference to the object looked for.
11045 if (obj->ReferencesObject(target)) {
11046 // Check instance filter if supplied. This is normally used to avoid
11047 // references from mirror objects (see Runtime_IsInPrototypeChain).
11048 if (!instance_filter->IsUndefined()) {
11049 Object* V = obj;
11050 while (true) {
11051 Object* prototype = V->GetPrototype();
11052 if (prototype->IsNull()) {
11053 break;
11054 }
11055 if (instance_filter == prototype) {
11056 obj = NULL; // Don't add this object.
11057 break;
11058 }
11059 V = prototype;
11060 }
11061 }
11062
11063 if (obj != NULL) {
11064 // Valid reference found add to instance array if supplied an update
11065 // count.
11066 if (instances != NULL && count < instances_size) {
11067 instances->set(count, obj);
11068 }
11069 last = obj;
11070 count++;
11071 }
11072 }
11073 }
11074 }
11075
11076 // Check for circular reference only. This can happen when the object is only
11077 // referenced from mirrors and has a circular reference in which case the
11078 // object is not really alive and would have been garbage collected if not
11079 // referenced from the mirror.
11080 if (count == 1 && last == target) {
11081 count = 0;
11082 }
11083
11084 // Return the number of referencing objects found.
11085 return count;
11086}
11087
11088
11089// Scan the heap for objects with direct references to an object
11090// args[0]: the object to find references to
11091// args[1]: constructor function for instances to exclude (Mirror)
11092// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011093RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011094 ASSERT(args.length() == 3);
11095
11096 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011097 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011098
11099 // Check parameters.
11100 CONVERT_CHECKED(JSObject, target, args[0]);
11101 Object* instance_filter = args[1];
11102 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11103 instance_filter->IsJSObject());
11104 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11105 RUNTIME_ASSERT(max_references >= 0);
11106
11107 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011108 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011109 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011110 JSFunction* arguments_function =
11111 JSFunction::cast(arguments_boilerplate->map()->constructor());
11112
11113 // Get the number of referencing objects.
11114 int count;
11115 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011116 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011117
11118 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011119 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011120 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011121 if (!maybe_object->ToObject(&object)) return maybe_object;
11122 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011123 FixedArray* instances = FixedArray::cast(object);
11124
11125 // Fill the referencing objects.
11126 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011127 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011128
11129 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011130 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011131 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11132 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011133 if (!maybe_result->ToObject(&result)) return maybe_result;
11134 }
11135 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011136 return result;
11137}
11138
11139
11140// Helper function used by Runtime_DebugConstructedBy below.
11141static int DebugConstructedBy(JSFunction* constructor, int max_references,
11142 FixedArray* instances, int instances_size) {
11143 AssertNoAllocation no_alloc;
11144
11145 // Iterate the heap.
11146 int count = 0;
11147 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011148 HeapObject* heap_obj = NULL;
11149 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011150 (max_references == 0 || count < max_references)) {
11151 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011152 if (heap_obj->IsJSObject()) {
11153 JSObject* obj = JSObject::cast(heap_obj);
11154 if (obj->map()->constructor() == constructor) {
11155 // Valid reference found add to instance array if supplied an update
11156 // count.
11157 if (instances != NULL && count < instances_size) {
11158 instances->set(count, obj);
11159 }
11160 count++;
11161 }
11162 }
11163 }
11164
11165 // Return the number of referencing objects found.
11166 return count;
11167}
11168
11169
11170// Scan the heap for objects constructed by a specific function.
11171// args[0]: the constructor to find instances of
11172// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011173RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011174 ASSERT(args.length() == 2);
11175
11176 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011177 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011178
11179 // Check parameters.
11180 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11181 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11182 RUNTIME_ASSERT(max_references >= 0);
11183
11184 // Get the number of referencing objects.
11185 int count;
11186 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11187
11188 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011189 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011190 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011191 if (!maybe_object->ToObject(&object)) return maybe_object;
11192 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011193 FixedArray* instances = FixedArray::cast(object);
11194
11195 // Fill the referencing objects.
11196 count = DebugConstructedBy(constructor, max_references, instances, count);
11197
11198 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011199 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011200 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11201 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011202 if (!maybe_result->ToObject(&result)) return maybe_result;
11203 }
11204 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011205 return result;
11206}
11207
11208
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011209// Find the effective prototype object as returned by __proto__.
11210// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011211RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011212 ASSERT(args.length() == 1);
11213
11214 CONVERT_CHECKED(JSObject, obj, args[0]);
11215
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011216 // Use the __proto__ accessor.
11217 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011218}
11219
11220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011221RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011222 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011223 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011224 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011225}
11226
11227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011228RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011229#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011230 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011231 ASSERT(args.length() == 1);
11232 // Get the function and make sure it is compiled.
11233 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011234 Handle<SharedFunctionInfo> shared(func->shared());
11235 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011236 return Failure::Exception();
11237 }
11238 func->code()->PrintLn();
11239#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011240 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011241}
ager@chromium.org9085a012009-05-11 19:22:57 +000011242
11243
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011244RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011245#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011246 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011247 ASSERT(args.length() == 1);
11248 // Get the function and make sure it is compiled.
11249 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011250 Handle<SharedFunctionInfo> shared(func->shared());
11251 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011252 return Failure::Exception();
11253 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011254 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011255#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011256 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011257}
11258
11259
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011260RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011261 NoHandleAllocation ha;
11262 ASSERT(args.length() == 1);
11263
11264 CONVERT_CHECKED(JSFunction, f, args[0]);
11265 return f->shared()->inferred_name();
11266}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011267
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011268
11269static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011270 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011271 AssertNoAllocation no_allocations;
11272
11273 int counter = 0;
11274 int buffer_size = buffer->length();
11275 HeapIterator iterator;
11276 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11277 ASSERT(obj != NULL);
11278 if (!obj->IsSharedFunctionInfo()) {
11279 continue;
11280 }
11281 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11282 if (shared->script() != script) {
11283 continue;
11284 }
11285 if (counter < buffer_size) {
11286 buffer->set(counter, shared);
11287 }
11288 counter++;
11289 }
11290 return counter;
11291}
11292
11293// For a script finds all SharedFunctionInfo's in the heap that points
11294// to this script. Returns JSArray of SharedFunctionInfo wrapped
11295// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011296RUNTIME_FUNCTION(MaybeObject*,
11297 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011298 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011299 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011300 CONVERT_CHECKED(JSValue, script_value, args[0]);
11301
11302 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11303
11304 const int kBufferSize = 32;
11305
11306 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011307 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011308 int number = FindSharedFunctionInfosForScript(*script, *array);
11309 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011310 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011311 FindSharedFunctionInfosForScript(*script, *array);
11312 }
11313
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011314 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011315 result->set_length(Smi::FromInt(number));
11316
11317 LiveEdit::WrapSharedFunctionInfos(result);
11318
11319 return *result;
11320}
11321
11322// For a script calculates compilation information about all its functions.
11323// The script source is explicitly specified by the second argument.
11324// The source of the actual script is not used, however it is important that
11325// all generated code keeps references to this particular instance of script.
11326// Returns a JSArray of compilation infos. The array is ordered so that
11327// each function with all its descendant is always stored in a continues range
11328// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011329RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011330 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011331 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011332 CONVERT_CHECKED(JSValue, script, args[0]);
11333 CONVERT_ARG_CHECKED(String, source, 1);
11334 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11335
11336 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11337
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011338 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011339 return Failure::Exception();
11340 }
11341
11342 return result;
11343}
11344
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011345// Changes the source of the script to a new_source.
11346// If old_script_name is provided (i.e. is a String), also creates a copy of
11347// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011348RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011349 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011350 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011351 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11352 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011353 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011354
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011355 CONVERT_CHECKED(Script, original_script_pointer,
11356 original_script_value->value());
11357 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011358
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011359 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11360 new_source,
11361 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011362
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011363 if (old_script->IsScript()) {
11364 Handle<Script> script_handle(Script::cast(old_script));
11365 return *(GetScriptWrapper(script_handle));
11366 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011367 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011368 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011369}
11370
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011372RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011373 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011374 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011375 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11376 return LiveEdit::FunctionSourceUpdated(shared_info);
11377}
11378
11379
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011380// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011381RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011382 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011383 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011384 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11385 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11386
ager@chromium.orgac091b72010-05-05 07:34:42 +000011387 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011388}
11389
11390// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011391RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011392 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011393 HandleScope scope(isolate);
11394 Handle<Object> function_object(args[0], isolate);
11395 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011396
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011397 if (function_object->IsJSValue()) {
11398 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11399 if (script_object->IsJSValue()) {
11400 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011401 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011402 }
11403
11404 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11405 } else {
11406 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11407 // and we check it in this function.
11408 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011409
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011410 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011411}
11412
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011413
11414// In a code of a parent function replaces original function as embedded object
11415// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011416RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011417 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011418 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011419
11420 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11421 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11422 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11423
11424 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11425 subst_wrapper);
11426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011427 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011428}
11429
11430
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011431// Updates positions of a shared function info (first parameter) according
11432// to script source change. Text change is described in second parameter as
11433// array of groups of 3 numbers:
11434// (change_begin, change_end, change_end_new_position).
11435// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011436RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011437 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011438 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011439 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11440 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11441
ager@chromium.orgac091b72010-05-05 07:34:42 +000011442 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011443}
11444
11445
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011446// For array of SharedFunctionInfo's (each wrapped in JSValue)
11447// checks that none of them have activations on stacks (of any thread).
11448// Returns array of the same length with corresponding results of
11449// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011450RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011451 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011452 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011453 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011454 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011455
ager@chromium.org357bf652010-04-12 11:30:10 +000011456 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011457}
11458
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011459// Compares 2 strings line-by-line, then token-wise and returns diff in form
11460// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11461// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011462RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011463 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011464 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011465 CONVERT_ARG_CHECKED(String, s1, 0);
11466 CONVERT_ARG_CHECKED(String, s2, 1);
11467
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011468 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011469}
11470
11471
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011472// A testing entry. Returns statement position which is the closest to
11473// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011474RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011475 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011476 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011477 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11478 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11479
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011480 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011481
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011482 if (code->kind() != Code::FUNCTION &&
11483 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011484 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011485 }
11486
11487 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011488 int closest_pc = 0;
11489 int distance = kMaxInt;
11490 while (!it.done()) {
11491 int statement_position = static_cast<int>(it.rinfo()->data());
11492 // Check if this break point is closer that what was previously found.
11493 if (source_position <= statement_position &&
11494 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011495 closest_pc =
11496 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011497 distance = statement_position - source_position;
11498 // Check whether we can't get any closer.
11499 if (distance == 0) break;
11500 }
11501 it.next();
11502 }
11503
11504 return Smi::FromInt(closest_pc);
11505}
11506
11507
ager@chromium.org357bf652010-04-12 11:30:10 +000011508// Calls specified function with or without entering the debugger.
11509// This is used in unit tests to run code as if debugger is entered or simply
11510// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011511RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011512 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011513 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011514 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11515 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11516
11517 Handle<Object> result;
11518 bool pending_exception;
11519 {
11520 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011521 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011522 &pending_exception);
11523 } else {
11524 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011525 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011526 &pending_exception);
11527 }
11528 }
11529 if (!pending_exception) {
11530 return *result;
11531 } else {
11532 return Failure::Exception();
11533 }
11534}
11535
11536
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011537// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011538RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011539 CONVERT_CHECKED(String, arg, args[0]);
11540 SmartPointer<char> flags =
11541 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11542 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011543 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011544}
11545
11546
11547// Performs a GC.
11548// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011549RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011550 isolate->heap()->CollectAllGarbage(true);
11551 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011552}
11553
11554
11555// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011556RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011557 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011558 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011559 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011560 }
11561 return Smi::FromInt(usage);
11562}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011563
11564
11565// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011566RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011567#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011568 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011569#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011570 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011571#endif
11572}
11573
11574
11575// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011576RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011577#ifdef LIVE_OBJECT_LIST
11578 return LiveObjectList::Capture();
11579#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011580 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011581#endif
11582}
11583
11584
11585// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011586RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011587#ifdef LIVE_OBJECT_LIST
11588 CONVERT_SMI_CHECKED(id, args[0]);
11589 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011590 return success ? isolate->heap()->true_value() :
11591 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011592#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011593 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011594#endif
11595}
11596
11597
11598// Generates the response to a debugger request for a dump of the objects
11599// contained in the difference between the captured live object lists
11600// specified by id1 and id2.
11601// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11602// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011603RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011604#ifdef LIVE_OBJECT_LIST
11605 HandleScope scope;
11606 CONVERT_SMI_CHECKED(id1, args[0]);
11607 CONVERT_SMI_CHECKED(id2, args[1]);
11608 CONVERT_SMI_CHECKED(start, args[2]);
11609 CONVERT_SMI_CHECKED(count, args[3]);
11610 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11611 EnterDebugger enter_debugger;
11612 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11613#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011614 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011615#endif
11616}
11617
11618
11619// Gets the specified object as requested by the debugger.
11620// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011621RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011622#ifdef LIVE_OBJECT_LIST
11623 CONVERT_SMI_CHECKED(obj_id, args[0]);
11624 Object* result = LiveObjectList::GetObj(obj_id);
11625 return result;
11626#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011627 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011628#endif
11629}
11630
11631
11632// Gets the obj id for the specified address if valid.
11633// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011634RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011635#ifdef LIVE_OBJECT_LIST
11636 HandleScope scope;
11637 CONVERT_ARG_CHECKED(String, address, 0);
11638 Object* result = LiveObjectList::GetObjId(address);
11639 return result;
11640#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011641 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011642#endif
11643}
11644
11645
11646// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011647RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011648#ifdef LIVE_OBJECT_LIST
11649 HandleScope scope;
11650 CONVERT_SMI_CHECKED(obj_id, args[0]);
11651 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11652 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11653 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11654 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11655 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11656
11657 Handle<JSObject> instance_filter;
11658 if (args[1]->IsJSObject()) {
11659 instance_filter = args.at<JSObject>(1);
11660 }
11661 bool verbose = false;
11662 if (args[2]->IsBoolean()) {
11663 verbose = args[2]->IsTrue();
11664 }
11665 int start = 0;
11666 if (args[3]->IsSmi()) {
11667 start = Smi::cast(args[3])->value();
11668 }
11669 int limit = Smi::kMaxValue;
11670 if (args[4]->IsSmi()) {
11671 limit = Smi::cast(args[4])->value();
11672 }
11673
11674 return LiveObjectList::GetObjRetainers(obj_id,
11675 instance_filter,
11676 verbose,
11677 start,
11678 limit,
11679 filter_obj);
11680#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011681 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011682#endif
11683}
11684
11685
11686// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011687RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011688#ifdef LIVE_OBJECT_LIST
11689 HandleScope scope;
11690 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11691 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11692 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11693
11694 Handle<JSObject> instance_filter;
11695 if (args[2]->IsJSObject()) {
11696 instance_filter = args.at<JSObject>(2);
11697 }
11698
11699 Object* result =
11700 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11701 return result;
11702#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011703 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011704#endif
11705}
11706
11707
11708// Generates the response to a debugger request for a list of all
11709// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011710RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011711#ifdef LIVE_OBJECT_LIST
11712 CONVERT_SMI_CHECKED(start, args[0]);
11713 CONVERT_SMI_CHECKED(count, args[1]);
11714 return LiveObjectList::Info(start, count);
11715#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011716 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011717#endif
11718}
11719
11720
11721// Gets a dump of the specified object as requested by the debugger.
11722// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011723RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011724#ifdef LIVE_OBJECT_LIST
11725 HandleScope scope;
11726 CONVERT_SMI_CHECKED(obj_id, args[0]);
11727 Object* result = LiveObjectList::PrintObj(obj_id);
11728 return result;
11729#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011730 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011731#endif
11732}
11733
11734
11735// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011736RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011737#ifdef LIVE_OBJECT_LIST
11738 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011739 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011740#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011741 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011742#endif
11743}
11744
11745
11746// Generates the response to a debugger request for a summary of the types
11747// of objects in the difference between the captured live object lists
11748// specified by id1 and id2.
11749// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11750// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011751RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011752#ifdef LIVE_OBJECT_LIST
11753 HandleScope scope;
11754 CONVERT_SMI_CHECKED(id1, args[0]);
11755 CONVERT_SMI_CHECKED(id2, args[1]);
11756 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11757
11758 EnterDebugger enter_debugger;
11759 return LiveObjectList::Summarize(id1, id2, filter_obj);
11760#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011761 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011762#endif
11763}
11764
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011765#endif // ENABLE_DEBUGGER_SUPPORT
11766
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011767
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011768#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011769RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011770 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011771 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011772
11773 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011774 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11775 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011776 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011777}
11778
11779
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011780RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011781 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011782 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011783
11784 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011785 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11786 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011787 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011788}
11789
11790#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011791
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011792// Finds the script object from the script data. NOTE: This operation uses
11793// heap traversal to find the function generated for the source position
11794// for the requested break point. For lazily compiled functions several heap
11795// traversals might be required rendering this operation as a rather slow
11796// operation. However for setting break points which is normally done through
11797// some kind of user interaction the performance is not crucial.
11798static Handle<Object> Runtime_GetScriptFromScriptName(
11799 Handle<String> script_name) {
11800 // Scan the heap for Script objects to find the script with the requested
11801 // script data.
11802 Handle<Script> script;
11803 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011804 HeapObject* obj = NULL;
11805 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011806 // If a script is found check if it has the script data requested.
11807 if (obj->IsScript()) {
11808 if (Script::cast(obj)->name()->IsString()) {
11809 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11810 script = Handle<Script>(Script::cast(obj));
11811 }
11812 }
11813 }
11814 }
11815
11816 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011817 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011818
11819 // Return the script found.
11820 return GetScriptWrapper(script);
11821}
11822
11823
11824// Get the script object from script data. NOTE: Regarding performance
11825// see the NOTE for GetScriptFromScriptData.
11826// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011827RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011828 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011829
11830 ASSERT(args.length() == 1);
11831
11832 CONVERT_CHECKED(String, script_name, args[0]);
11833
11834 // Find the requested script.
11835 Handle<Object> result =
11836 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11837 return *result;
11838}
11839
11840
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011841// Determines whether the given stack frame should be displayed in
11842// a stack trace. The caller is the error constructor that asked
11843// for the stack trace to be collected. The first time a construct
11844// call to this function is encountered it is skipped. The seen_caller
11845// in/out parameter is used to remember if the caller has been seen
11846// yet.
11847static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11848 bool* seen_caller) {
11849 // Only display JS frames.
11850 if (!raw_frame->is_java_script())
11851 return false;
11852 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11853 Object* raw_fun = frame->function();
11854 // Not sure when this can happen but skip it just in case.
11855 if (!raw_fun->IsJSFunction())
11856 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011857 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011858 *seen_caller = true;
11859 return false;
11860 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011861 // Skip all frames until we've seen the caller. Also, skip the most
11862 // obvious builtin calls. Some builtin calls (such as Number.ADD
11863 // which is invoked using 'call') are very difficult to recognize
11864 // so we're leaving them in for now.
11865 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011866}
11867
11868
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011869// Collect the raw data for a stack trace. Returns an array of 4
11870// element segments each containing a receiver, function, code and
11871// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011872RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011873 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011874 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011875 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11876
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011877 HandleScope scope(isolate);
11878 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011879
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011880 limit = Max(limit, 0); // Ensure that limit is not negative.
11881 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011882 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011883 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011884
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011885 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011886 // If the caller parameter is a function we skip frames until we're
11887 // under it before starting to collect.
11888 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011889 int cursor = 0;
11890 int frames_seen = 0;
11891 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011892 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011893 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011894 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011895 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011896 // Set initial size to the maximum inlining level + 1 for the outermost
11897 // function.
11898 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011899 frame->Summarize(&frames);
11900 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011901 if (cursor + 4 > elements->length()) {
11902 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11903 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011904 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011905 for (int i = 0; i < cursor; i++) {
11906 new_elements->set(i, elements->get(i));
11907 }
11908 elements = new_elements;
11909 }
11910 ASSERT(cursor + 4 <= elements->length());
11911
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011912 Handle<Object> recv = frames[i].receiver();
11913 Handle<JSFunction> fun = frames[i].function();
11914 Handle<Code> code = frames[i].code();
11915 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011916 elements->set(cursor++, *recv);
11917 elements->set(cursor++, *fun);
11918 elements->set(cursor++, *code);
11919 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011920 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011921 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011922 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011923 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011924 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011925 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011926 return *result;
11927}
11928
11929
ager@chromium.org3811b432009-10-28 14:53:37 +000011930// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011931RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011932 ASSERT_EQ(args.length(), 0);
11933
11934 NoHandleAllocation ha;
11935
11936 const char* version_string = v8::V8::GetVersion();
11937
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011938 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
11939 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000011940}
11941
11942
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011943RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011944 ASSERT(args.length() == 2);
11945 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11946 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011947 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011948 OS::Abort();
11949 UNREACHABLE();
11950 return NULL;
11951}
11952
11953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011954RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011955 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011956 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011957 Object* key = args[1];
11958
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011959 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011960 Object* o = cache->get(finger_index);
11961 if (o == key) {
11962 // The fastest case: hit the same place again.
11963 return cache->get(finger_index + 1);
11964 }
11965
11966 for (int i = finger_index - 2;
11967 i >= JSFunctionResultCache::kEntriesIndex;
11968 i -= 2) {
11969 o = cache->get(i);
11970 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011971 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011972 return cache->get(i + 1);
11973 }
11974 }
11975
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011976 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011977 ASSERT(size <= cache->length());
11978
11979 for (int i = size - 2; i > finger_index; i -= 2) {
11980 o = cache->get(i);
11981 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011982 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011983 return cache->get(i + 1);
11984 }
11985 }
11986
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011987 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011988 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011989
11990 Handle<JSFunctionResultCache> cache_handle(cache);
11991 Handle<Object> key_handle(key);
11992 Handle<Object> value;
11993 {
11994 Handle<JSFunction> factory(JSFunction::cast(
11995 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11996 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011997 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011998 // This handle is nor shared, nor used later, so it's safe.
11999 Object** argv[] = { key_handle.location() };
12000 bool pending_exception = false;
12001 value = Execution::Call(factory,
12002 receiver,
12003 1,
12004 argv,
12005 &pending_exception);
12006 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012007 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012008
12009#ifdef DEBUG
12010 cache_handle->JSFunctionResultCacheVerify();
12011#endif
12012
12013 // Function invocation may have cleared the cache. Reread all the data.
12014 finger_index = cache_handle->finger_index();
12015 size = cache_handle->size();
12016
12017 // If we have spare room, put new data into it, otherwise evict post finger
12018 // entry which is likely to be the least recently used.
12019 int index = -1;
12020 if (size < cache_handle->length()) {
12021 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12022 index = size;
12023 } else {
12024 index = finger_index + JSFunctionResultCache::kEntrySize;
12025 if (index == cache_handle->length()) {
12026 index = JSFunctionResultCache::kEntriesIndex;
12027 }
12028 }
12029
12030 ASSERT(index % 2 == 0);
12031 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12032 ASSERT(index < cache_handle->length());
12033
12034 cache_handle->set(index, *key_handle);
12035 cache_handle->set(index + 1, *value);
12036 cache_handle->set_finger_index(index);
12037
12038#ifdef DEBUG
12039 cache_handle->JSFunctionResultCacheVerify();
12040#endif
12041
12042 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012043}
12044
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012046RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012047 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012048 CONVERT_ARG_CHECKED(String, type, 0);
12049 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012050 return *isolate->factory()->NewJSMessageObject(
12051 type,
12052 arguments,
12053 0,
12054 0,
12055 isolate->factory()->undefined_value(),
12056 isolate->factory()->undefined_value(),
12057 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012058}
12059
12060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012061RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012062 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12063 return message->type();
12064}
12065
12066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012067RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012068 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12069 return message->arguments();
12070}
12071
12072
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012073RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012074 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12075 return Smi::FromInt(message->start_position());
12076}
12077
12078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012079RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012080 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12081 return message->script();
12082}
12083
12084
kasper.lund44510672008-07-25 07:37:58 +000012085#ifdef DEBUG
12086// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12087// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012088RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012089 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012090 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012091#define COUNT_ENTRY(Name, argc, ressize) + 1
12092 int entry_count = 0
12093 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12094 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12095 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12096#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012097 Factory* factory = isolate->factory();
12098 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012099 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012100 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012101#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012102 { \
12103 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012104 Handle<String> name; \
12105 /* Inline runtime functions have an underscore in front of the name. */ \
12106 if (inline_runtime_functions) { \
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 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012110 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012111 Vector<const char>(#Name, StrLength(#Name))); \
12112 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012113 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012114 pair_elements->set(0, *name); \
12115 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012116 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012117 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012118 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012119 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012120 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012121 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012122 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012123 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012124#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012125 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012126 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012127 return *result;
12128}
kasper.lund44510672008-07-25 07:37:58 +000012129#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012130
12131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012132RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012133 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012134 CONVERT_CHECKED(String, format, args[0]);
12135 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012136 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012137 LOGGER->LogRuntime(chars, elms);
12138 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012139}
12140
12141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012142RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012143 UNREACHABLE(); // implemented as macro in the parser
12144 return NULL;
12145}
12146
12147
12148// ----------------------------------------------------------------------------
12149// Implementation of Runtime
12150
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012151#define F(name, number_of_args, result_size) \
12152 { Runtime::k##name, Runtime::RUNTIME, #name, \
12153 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012154
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012155
12156#define I(name, number_of_args, result_size) \
12157 { Runtime::kInline##name, Runtime::INLINE, \
12158 "_" #name, NULL, number_of_args, result_size },
12159
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012160static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012161 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012162 INLINE_FUNCTION_LIST(I)
12163 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012164};
12165
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012166
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012167MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12168 Object* dictionary) {
12169 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012170 ASSERT(dictionary != NULL);
12171 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12172 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012173 Object* name_symbol;
12174 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012175 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012176 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12177 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012178 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012179 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12180 String::cast(name_symbol),
12181 Smi::FromInt(i),
12182 PropertyDetails(NONE, NORMAL));
12183 if (!maybe_dictionary->ToObject(&dictionary)) {
12184 // Non-recoverable failure. Calling code must restart heap
12185 // initialization.
12186 return maybe_dictionary;
12187 }
12188 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012189 }
12190 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012191}
12192
12193
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012194const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12195 Heap* heap = name->GetHeap();
12196 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012197 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012198 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012199 int function_index = Smi::cast(smi_index)->value();
12200 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012201 }
12202 return NULL;
12203}
12204
12205
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012206const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012207 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12208}
12209
12210
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012211void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012212 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012213 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012214 if (failure->IsRetryAfterGC()) {
12215 // Try to do a garbage collection; ignore it if it fails. The C
12216 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012217 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012218 } else {
12219 // Handle last resort GC and make sure to allow future allocations
12220 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012221 isolate->counters()->gc_last_resort_from_js()->Increment();
12222 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012223 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012224}
12225
12226
12227} } // namespace v8::internal